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
020package org.crsh.standalone;
021
022import org.crsh.plugin.PluginContext;
023import org.crsh.plugin.PluginLifeCycle;
024import org.crsh.plugin.ServiceLoaderDiscovery;
025import org.crsh.vfs.FS;
026import org.crsh.vfs.Path;
027import org.crsh.vfs.spi.FSDriver;
028
029import java.io.File;
030import java.io.IOException;
031import java.net.URISyntaxException;
032import java.net.URL;
033import java.net.URLClassLoader;
034import java.util.Collections;
035import java.util.Map;
036import java.util.logging.Logger;
037
038/**
039 * A boostrap for starting a standalone CRaSH.
040 */
041public 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}