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 = new FS();
048    
049      /** The command file system. */
050      private final FS cmdFS = new FS();
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       * @throws NullPointerException if the loader argument is null
063       */
064      public Bootstrap(ClassLoader baseLoader) throws NullPointerException {
065        if (baseLoader == null) {
066          throw new NullPointerException("No null base loader accepted");
067        }
068        this.attributes = Collections.emptyMap();
069        this.loader = new URLClassLoader(new URL[]{}, baseLoader);
070      }
071    
072      /**
073       * Replaces the attributes to use, the new attributes map will be used as is and not copied.
074       *
075       * @param attributes the attribute map
076       */
077      public void setAttributes(Map<String, Object> attributes) {
078        this.attributes = attributes;
079      }
080    
081      /**
082       * Add a configuration path driver.
083       *
084       * @param driver the configuration driver
085       * @return this bootstrap
086       * @throws NullPointerException when the driver is null
087       */
088      public Bootstrap addToConfPath(FSDriver<?> driver) throws NullPointerException {
089        if (driver == null) {
090          throw new NullPointerException("No null conf driver");
091        }
092        log.info("Added " + driver + " driver to conf path");
093        confFS.mount(driver);
094        return this;
095      }
096    
097      /**
098       * Add a configuration path directory.
099       *
100       * @param path the configuration path
101       * @return this bootstrap
102       * @throws NullPointerException when the path argument is null
103       * @throws IOException any io exception
104       */
105      public Bootstrap addToConfPath(File path) throws NullPointerException, IOException {
106        if (path == null) {
107          throw new NullPointerException("No null conf path");
108        }
109        log.info("Added " + path.getCanonicalPath() + " file to conf path");
110        confFS.mount(path);
111        return this;
112      }
113    
114      /**
115       * Add a configuration path.
116       *
117       * @param path the configuration path
118       * @return this bootstrap
119       * @throws NullPointerException when the path argument is null
120       * @throws IOException any io exception
121       * @throws URISyntaxException any uri syntax exception
122       */
123      public Bootstrap addToConfPath(Path path) throws NullPointerException, IOException, URISyntaxException {
124        if (path == null) {
125          throw new NullPointerException("No null conf path");
126        }
127        log.info("Added " + path.getValue() + " path to conf path");
128        confFS.mount(loader, path);
129        return this;
130      }
131    
132      /**
133       * Add a command path driver.
134       *
135       * @param driver the command driver
136       * @return this bootstrap
137       * @throws NullPointerException when the driver is null
138       */
139      public Bootstrap addToCmdPath(FSDriver<?> driver) throws NullPointerException {
140        if (driver == null) {
141          throw new NullPointerException("No null conf driver");
142        }
143        log.info("Added " + driver + " driver to command path");
144        cmdFS.mount(driver);
145        return this;
146      }
147    
148      /**
149       * Add a command path directory.
150       *
151       * @param path the command path
152       * @return this bootstrap
153       * @throws NullPointerException when the path argument is null
154       * @throws IOException any io exception
155       */
156      public Bootstrap addToCmdPath(File path) throws NullPointerException, IOException {
157        if (path == null) {
158          throw new NullPointerException("No null command path");
159        }
160        log.info("Added " + path.getAbsolutePath() + " file to command path");
161        cmdFS.mount(path);
162        return this;
163      }
164    
165      /**
166       * Add a command path directory.
167       *
168       * @param path the command path
169       * @return this bootstrap
170       * @throws NullPointerException when the path argument is null
171       * @throws IOException any io exception
172       * @throws URISyntaxException any uri syntax exception
173       */
174      public Bootstrap addToCmdPath(Path path) throws NullPointerException, IOException, URISyntaxException {
175        if (path == null) {
176          throw new NullPointerException("No null command path");
177        }
178        log.info("Added " + path.getValue() + " path to command path");
179        cmdFS.mount(loader, path);
180        return this;
181      }
182    
183      /**
184       * Trigger the boostrap.
185       *
186       * @throws Exception any exception that would prevent the bootstrap
187       */
188      public void bootstrap() throws Exception {
189    
190        // The service loader discovery
191        ServiceLoaderDiscovery discovery = new ServiceLoaderDiscovery(loader);
192    
193        //
194        PluginContext context = new PluginContext(
195          discovery,
196          attributes,
197          cmdFS,
198          confFS,
199          loader);
200    
201        //
202        context.refresh();
203    
204        //
205        start(context);
206      }
207    
208      public void shutdown() {
209        stop();
210      }
211    }