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.standalone;
021    
022    import org.crsh.plugin.PluginContext;
023    import org.crsh.plugin.PluginLifeCycle;
024    import org.crsh.plugin.ServiceLoaderDiscovery;
025    import org.crsh.vfs.FS;
026    import org.crsh.vfs.Path;
027    import org.crsh.vfs.spi.FSDriver;
028    
029    import java.io.File;
030    import java.io.IOException;
031    import java.net.URISyntaxException;
032    import java.net.URL;
033    import java.net.URLClassLoader;
034    import java.util.Collections;
035    import java.util.Map;
036    import java.util.logging.Logger;
037    
038    /**
039     * A boostrap for starting a standalone CRaSH.
040     */
041    public class Bootstrap extends PluginLifeCycle {
042    
043      /** . */
044      protected final Logger log = Logger.getLogger(getClass().getName());
045    
046      /** The configuration file system. */
047      private final FS confFS;
048    
049      /** The command file system. */
050      private final FS cmdFS;
051    
052      /** The base classloader. */
053      private final ClassLoader loader;
054    
055      /** The attributes. */
056      private Map<String, Object> attributes;
057    
058      /**
059       * Create a bootstrap instance with the base classloader and an empty and unmodifiable attribute map.
060       *
061       * @param baseLoader the base classloader crash will use
062       * @param confFS the conf file system
063       * @param cmdFS the cmd file system
064       * @throws NullPointerException if any argument is null
065       */
066      public Bootstrap(ClassLoader baseLoader, FS confFS, FS cmdFS) throws NullPointerException {
067        if (baseLoader == null) {
068          throw new NullPointerException("No null base loader accepted");
069        }
070        if (confFS == null) {
071          throw new NullPointerException("No null conf file system accepted");
072        }
073        if (cmdFS == null) {
074          throw new NullPointerException("No null cmd file system accepted");
075        }
076        this.attributes = Collections.emptyMap();
077        this.confFS = confFS;
078        this.cmdFS = cmdFS;
079        this.loader = new URLClassLoader(new URL[]{}, baseLoader);
080      }
081    
082      /**
083       * Create a bootstrap instance with the base classloader and an empty and unmodifiable attribute map.
084       *
085       * @param baseLoader the base classloader crash will use
086       * @throws NullPointerException if any argument is null
087       */
088      public Bootstrap(ClassLoader baseLoader) throws NullPointerException {
089        this(baseLoader, new FS(), new FS());
090      }
091    
092      /**
093       * Replaces the attributes to use, the new attributes map will be used as is and not copied.
094       *
095       * @param attributes the attribute map
096       */
097      public void setAttributes(Map<String, Object> attributes) {
098        this.attributes = attributes;
099      }
100    
101      /**
102       * Add a configuration path driver.
103       *
104       * @param driver the configuration driver
105       * @return this bootstrap
106       * @throws NullPointerException when the driver is null
107       * @throws IOException any io exception
108       */
109      public Bootstrap addToConfPath(FSDriver<?> driver) throws IOException, NullPointerException {
110        if (driver == null) {
111          throw new NullPointerException("No null conf driver");
112        }
113        log.info("Added " + driver + " driver to conf path");
114        confFS.mount(driver);
115        return this;
116      }
117    
118      /**
119       * Add a configuration path directory.
120       *
121       * @param path the configuration path
122       * @return this bootstrap
123       * @throws NullPointerException when the path argument is null
124       * @throws IOException any io exception
125       */
126      public Bootstrap addToConfPath(File path) throws NullPointerException, IOException {
127        if (path == null) {
128          throw new NullPointerException("No null conf path");
129        }
130        log.info("Added " + path.getCanonicalPath() + " file to conf path");
131        confFS.mount(path);
132        return this;
133      }
134    
135      /**
136       * Add a configuration path.
137       *
138       * @param path the configuration path
139       * @return this bootstrap
140       * @throws NullPointerException when the path argument is null
141       * @throws IOException any io exception
142       * @throws URISyntaxException any uri syntax exception
143       */
144      public Bootstrap addToConfPath(Path path) throws NullPointerException, IOException, URISyntaxException {
145        if (path == null) {
146          throw new NullPointerException("No null conf path");
147        }
148        log.info("Added " + path.getValue() + " path to conf path");
149        confFS.mount(loader, path);
150        return this;
151      }
152    
153      /**
154       * Add a command path driver.
155       *
156       * @param driver the command driver
157       * @return this bootstrap
158       * @throws NullPointerException when the driver is null
159       * @throws IOException any io exception
160       */
161      public Bootstrap addToCmdPath(FSDriver<?> driver) throws IOException, NullPointerException {
162        if (driver == null) {
163          throw new NullPointerException("No null conf driver");
164        }
165        log.info("Added " + driver + " driver to command path");
166        cmdFS.mount(driver);
167        return this;
168      }
169    
170      /**
171       * Add a command path directory.
172       *
173       * @param path the command path
174       * @return this bootstrap
175       * @throws NullPointerException when the path argument is null
176       * @throws IOException any io exception
177       */
178      public Bootstrap addToCmdPath(File path) throws NullPointerException, IOException {
179        if (path == null) {
180          throw new NullPointerException("No null command path");
181        }
182        log.info("Added " + path.getAbsolutePath() + " file to command path");
183        cmdFS.mount(path);
184        return this;
185      }
186    
187      /**
188       * Add a command path directory.
189       *
190       * @param path the command path
191       * @return this bootstrap
192       * @throws NullPointerException when the path argument is null
193       * @throws IOException any io exception
194       * @throws URISyntaxException any uri syntax exception
195       */
196      public Bootstrap addToCmdPath(Path path) throws NullPointerException, IOException, URISyntaxException {
197        if (path == null) {
198          throw new NullPointerException("No null command path");
199        }
200        log.info("Added " + path.getValue() + " path to command path");
201        cmdFS.mount(loader, path);
202        return this;
203      }
204    
205      /**
206       * Trigger the boostrap.
207       *
208       * @throws Exception any exception that would prevent the bootstrap
209       */
210      public void bootstrap() throws Exception {
211    
212        // The service loader discovery
213        ServiceLoaderDiscovery discovery = new ServiceLoaderDiscovery(loader);
214    
215        //
216        PluginContext context = new PluginContext(
217          discovery,
218          attributes,
219          cmdFS,
220          confFS,
221          loader);
222    
223        //
224        context.refresh();
225    
226        //
227        start(context);
228      }
229    
230      public void shutdown() {
231        stop();
232      }
233    }