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 java.io.IOException;
023    import java.util.logging.Level;
024    import java.util.logging.Logger;
025    
026    abstract class FileSystemAction {
027    
028      /** . */
029      private static final Logger log = Logger.getLogger(FileSystemAction.class.getName());
030    
031      public static void read(SCPCommand cmd, FileSystem fs) throws IOException {
032        cmd.ack();
033        log.log(Level.FINE, "Want to read line");
034        String line = cmd.readLine();
035        log.log(Level.FINE, "Read line " + line);
036        FileSystemAction action = decode(line);
037        log.log(Level.FINE, "Action: " + action);
038        read(cmd, action, fs);
039      }
040    
041      private static void read(final SCPCommand cmd, FileSystemAction action, FileSystem fs) throws IOException {
042        if (action instanceof StartDirectory) {
043          String directoryName = ((StartDirectory)action).name;
044          fs.beginDirectory(directoryName);
045    
046          //
047          cmd.ack();
048    
049          //
050          while (true) {
051            String nextLine = cmd.readLine();
052            FileSystemAction nextAction = decode(nextLine);
053            log.log(Level.FINE, "Next action: " + nextAction);
054            if (nextAction instanceof FileSystemAction.EndDirectory) {
055              fs.endDirectory(directoryName);
056              break;
057            } else {
058              read(cmd, nextAction, fs);
059            }
060          }
061    
062          //
063          cmd.ack();
064        } else if (action instanceof File) {
065          File file = (File)action;
066    
067          //
068          cmd.ack();
069    
070          //
071          fs.file(file.name, file.length, cmd.read(file.length));
072    
073          //
074          log.log(Level.FINE, "About to send ack for file");
075          cmd.ack();
076          cmd.readAck();
077        }
078      }
079    
080      private static FileSystemAction decode(String line) {
081        if (line == null) {
082          throw new NullPointerException();
083        }
084        if (line.length() == 0) {
085          throw new IllegalArgumentException("Line has length zero");
086        }
087        char t = line.charAt(0);
088        if (t == 'C' || t == 'D') {
089    
090          //
091          int length;
092          int endLength = line.indexOf(' ', 6);
093          if (endLength == -1) {
094            throw new IllegalArgumentException();
095          } else {
096            String s = line.substring(6, endLength);
097            if (s.length() == 1 && s.charAt(0) == '0') {
098              // Optimize for directories
099              length = 0;
100            } else {
101              try {
102                length = Integer.parseInt(s);
103              }
104              catch (NumberFormatException e) {
105                throw new IllegalArgumentException("Could not parse file length " + s);
106              }
107            }
108          }
109    
110          //
111          String name = line.substring(endLength + 1);
112    
113          //
114          if (t == 'D') {
115            return new StartDirectory(name);
116          } else {
117            return new File(name, length);
118          }
119        } else if (t == 'E') {
120          return new EndDirectory();
121        } else {
122          throw new IllegalArgumentException("Could not recognize file system action " + line);
123        }
124      }
125    
126      private static class StartDirectory extends FileSystemAction {
127    
128        /** . */
129        private final String name;
130    
131        private StartDirectory(String name) {
132          this.name = name;
133        }
134    
135        @Override
136        public String toString() {
137          return "StartDirectory[name=" + name + "]";
138        }
139      }
140    
141      private static class File extends FileSystemAction {
142    
143        /** . */
144        private final String name;
145    
146        /** . */
147        private final int length;
148    
149        private File(String name, int length) {
150          this.name = name;
151          this.length = length;
152        }
153    
154        @Override
155        public String toString() {
156          return "File[name=" + name + ",length=" + length + "]";
157        }
158      }
159    
160      private static class EndDirectory extends FileSystemAction {
161        private EndDirectory() {
162        }
163    
164        @Override
165        public String toString() {
166          return "EndDirectory[]";
167        }
168      }
169    }