001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.jcr;
021    
022    import org.slf4j.Logger;
023    import org.slf4j.LoggerFactory;
024    
025    import java.io.IOException;
026    
027    abstract class FileSystemAction {
028    
029      /** . */
030      private static final Logger log = LoggerFactory.getLogger(FileSystemAction.class);
031    
032      public static void read(SCPCommand cmd, FileSystem fs) throws IOException {
033        cmd.ack();
034        log.debug("Want to read line");
035        String line = cmd.readLine();
036        log.debug("Read line " + line);
037        FileSystemAction action = decode(line);
038        log.debug("Action: " + action);
039        read(cmd, action, fs);
040      }
041    
042      private static void read(final SCPCommand cmd, FileSystemAction action, FileSystem fs) throws IOException {
043        if (action instanceof StartDirectory) {
044          String directoryName = ((StartDirectory)action).name;
045          fs.startDirectory(directoryName);
046    
047          //
048          cmd.ack();
049    
050          //
051          while (true) {
052            String nextLine = cmd.readLine();
053            FileSystemAction nextAction = decode(nextLine);
054            log.debug("Next action: " + nextAction);
055            if (nextAction instanceof FileSystemAction.EndDirectory) {
056              fs.endDirectory(directoryName);
057              break;
058            } else {
059              read(cmd, nextAction, fs);
060            }
061          }
062    
063          //
064          cmd.ack();
065        } else if (action instanceof File) {
066          File file = (File)action;
067    
068          //
069          cmd.ack();
070    
071          //
072          fs.file(file.name, file.length, cmd.read(file.length));
073    
074          //
075          log.debug("About to send ack for file");
076          cmd.ack();
077          cmd.readAck();
078        }
079      }
080    
081      private static FileSystemAction decode(String line) {
082        if (line == null) {
083          throw new NullPointerException();
084        }
085        if (line.length() == 0) {
086          throw new IllegalArgumentException("Line has length zero");
087        }
088        char t = line.charAt(0);
089        if (t == 'C' || t == 'D') {
090    
091          //
092          int length;
093          int endLength = line.indexOf(' ', 6);
094          if (endLength == -1) {
095            throw new IllegalArgumentException();
096          } else {
097            String s = line.substring(6, endLength);
098            if (s.length() == 1 && s.charAt(0) == '0') {
099              // Optimize for directories
100              length = 0;
101            } else {
102              try {
103                length = Integer.parseInt(s);
104              }
105              catch (NumberFormatException e) {
106                throw new IllegalArgumentException("Could not parse file length " + s);
107              }
108            }
109          }
110    
111          //
112          String name = line.substring(endLength + 1);
113    
114          //
115          if (t == 'D') {
116            return new StartDirectory(name);
117          } else {
118            return new File(name, length);
119          }
120        } else if (t == 'E') {
121          return new EndDirectory();
122        } else {
123          throw new IllegalArgumentException("Could not recognize file system action " + line);
124        }
125      }
126    
127      private static class StartDirectory extends FileSystemAction {
128    
129        /** . */
130        private final String name;
131    
132        private StartDirectory(String name) {
133          this.name = name;
134        }
135    
136        @Override
137        public String toString() {
138          return "StartDirectory[name=" + name + "]";
139        }
140      }
141    
142      private static class File extends FileSystemAction {
143    
144        /** . */
145        private final String name;
146    
147        /** . */
148        private final int length;
149    
150        private File(String name, int length) {
151          this.name = name;
152          this.length = length;
153        }
154    
155        @Override
156        public String toString() {
157          return "File[name=" + name + ",length=" + length + "]";
158        }
159      }
160    
161      private static class EndDirectory extends FileSystemAction {
162        private EndDirectory() {
163        }
164    
165        @Override
166        public String toString() {
167          return "EndDirectory[]";
168        }
169      }
170    }