View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.argeo.slc.cli;
17  
18  import java.io.File;
19  import java.io.FileOutputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.lang.reflect.Method;
23  import java.security.AccessController;
24  import java.security.PrivilegedAction;
25  import java.util.ArrayList;
26  import java.util.Date;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.ServiceLoader;
31  import java.util.UUID;
32  
33  import javax.security.auth.Subject;
34  import javax.security.auth.login.LoginContext;
35  
36  import org.argeo.osgi.boot.OsgiBoot;
37  import org.osgi.framework.BundleContext;
38  import org.osgi.framework.ServiceReference;
39  import org.osgi.framework.launch.Framework;
40  import org.osgi.framework.launch.FrameworkFactory;
41  
42  /** Configures an SLC runtime and runs a process. */
43  public class SlcMain implements PrivilegedAction<String> {
44  	public final static String NIX = "NIX";
45  	public final static String WINDOWS = "WINDOWS";
46  	public final static String SOLARIS = "SOLARIS";
47  
48  	public final static String os;
49  	public final static String slcDirName = ".slc";
50  	final static File homeDir = new File(System.getProperty("user.home"));
51  
52  	static {
53  		String osName = System.getProperty("os.name");
54  		if (osName.startsWith("Win"))
55  			os = WINDOWS;
56  		else if (osName.startsWith("Solaris"))
57  			os = SOLARIS;
58  		else
59  			os = NIX;
60  	}
61  
62  	private Long timeout = 30 * 1000l;
63  	private final String[] args;
64  	private final File confDir;
65  	private final File dataDir;
66  	private final File modulesDir;
67  
68  	private final List<String> bundlesToStart = new ArrayList<String>();
69  
70  	public SlcMain(String[] args, File confDir, File dataDir, File modulesDir) {
71  		this.args = args;
72  		this.confDir = confDir;
73  		this.dataDir = dataDir;
74  		this.modulesDir = modulesDir;
75  
76  		bundlesToStart.add("org.eclipse.equinox.cm");
77  		bundlesToStart.add("org.argeo.cms");
78  		bundlesToStart.add("org.eclipse.gemini.blueprint.extender");
79  		bundlesToStart.add("org.argeo.slc.agent");
80  		bundlesToStart.add("org.argeo.slc.agent.jcr");
81  
82  		// bundlesToStart.add("org.springframework.osgi.extender");
83  		// bundlesToStart.add("org.argeo.node.repo.jackrabbit");
84  		// bundlesToStart.add("org.argeo.security.dao.os");
85  		// bundlesToStart.add("org.argeo.slc.node.jackrabbit");
86  		// bundlesToStart.add("org.argeo.slc.agent");
87  		// bundlesToStart.add("org.argeo.slc.agent.jcr");
88  		// if (args.length == 0)
89  		// bundlesToStart.add("org.argeo.slc.support.equinox");
90  		// bundlesToStart.add("org.argeo.slc.agent.cli");
91  	}
92  
93  	public String run() {
94  		long begin = System.currentTimeMillis();
95  
96  		Framework framework = null;
97  		try {
98  			info("## Date : " + new Date());
99  			info("## Data : " + dataDir.getCanonicalPath());
100 
101 			// Start Equinox
102 			ServiceLoader<FrameworkFactory> ff = ServiceLoader.load(FrameworkFactory.class);
103 			FrameworkFactory frameworkFactory = ff.iterator().next();
104 			Map<String, String> configuration = new HashMap<String, String>();
105 			configuration.put("osgi.configuration.area", confDir.getCanonicalPath());
106 			configuration.put("osgi.instance.area", dataDir.getCanonicalPath());
107 			// Do clean
108 			configuration.put("osgi.clean", "true");
109 			if (args.length == 0) {
110 				configuration.put("osgi.console", "");
111 			}
112 
113 			// Spring configs currently require System properties
114 			System.getProperties().putAll(configuration);
115 
116 			framework = frameworkFactory.newFramework(configuration);
117 			framework.start();
118 			BundleContext bundleContext = framework.getBundleContext();
119 
120 			// OSGi bootstrap
121 			OsgiBoot osgiBoot = new OsgiBoot(bundleContext);
122 
123 			// working copy modules
124 			if (modulesDir.exists())
125 				osgiBoot.installUrls(osgiBoot.getBundlesUrls(modulesDir.getCanonicalPath() + ";in=*;ex=.gitignore"));
126 
127 			// system modules
128 			if (System.getProperty(OsgiBoot.PROP_ARGEO_OSGI_BUNDLES) != null)
129 				osgiBoot.installUrls(osgiBoot.getBundlesUrls(System.getProperty(OsgiBoot.PROP_ARGEO_OSGI_BUNDLES)));
130 			else
131 				osgiBoot.installUrls(osgiBoot.getBundlesUrls(System.getProperty("user.home") + "/.slc/modules/;in=**"));
132 
133 			// Start runtime
134 			osgiBoot.startBundles(bundlesToStart);
135 
136 			// Find SLC Agent
137 			ServiceReference sr = null;
138 			while (sr == null) {
139 				sr = bundleContext.getServiceReference("org.argeo.slc.execution.SlcAgentCli");
140 				if (System.currentTimeMillis() - begin > timeout)
141 					throw new RuntimeException("Cannot find SLC agent CLI");
142 				Thread.sleep(100);
143 			}
144 			Object agentCli = bundleContext.getService(sr);
145 
146 			// Initialization completed
147 			long duration = System.currentTimeMillis() - begin;
148 			info("[[ Initialized in " + (duration / 1000) + "s " + (duration % 1000) + "ms ]]");
149 
150 			if (args.length == 0)
151 				return null;// console mode
152 
153 			// Subject.doAs(Subject.getSubject(AccessController.getContext()),
154 			// new AgentCliCall(agentCli));
155 			Class<?>[] parameterTypes = { String[].class };
156 			Method method = agentCli.getClass().getMethod("process", parameterTypes);
157 			Object[] methodArgs = { args };
158 			Object ret = method.invoke(agentCli, methodArgs);
159 
160 			// Shutdown OSGi runtime
161 			framework.stop();
162 			framework.waitForStop(60 * 1000);
163 
164 			return ret.toString();
165 		} catch (Exception e) {
166 			// Shutdown OSGi runtime
167 			if (framework != null)
168 				try {
169 					framework.stop();
170 					framework.waitForStop(15 * 1000);
171 				} catch (Exception silent) {
172 				}
173 			throw new RuntimeException("Cannot run SLC command line", e);
174 		} finally {
175 
176 		}
177 	}
178 
179 	public static void main(String[] args) {
180 		try {
181 			// Prepare directories
182 			File executionDir = new File(System.getProperty("user.dir"));
183 			File slcDir;
184 			Boolean isTransient = false;
185 			if (isTransient) {
186 				File tempDir = new File(System.getProperty("java.io.tmpdir") + "/" + System.getProperty("user.name"));
187 				slcDir = new File(tempDir, "slc-" + UUID.randomUUID().toString());
188 				slcDir.mkdirs();
189 				System.setProperty("argeo.node.repo.configuration", "osgibundle:repository-memory.xml");
190 			} else {
191 				slcDir = findSlcDir(executionDir);
192 				if (slcDir == null) {
193 					slcDir = new File(executionDir, slcDirName);
194 					slcDir.mkdirs();
195 					info("## Creating an SLC node at " + slcDir + " ...");
196 				}
197 			}
198 
199 			File dataDir = new File(slcDir, "data");
200 			if (!dataDir.exists())
201 				dataDir.mkdirs();
202 
203 			File confDir = new File(slcDir, "conf");
204 			if (!confDir.exists())
205 				confDir.mkdirs();
206 
207 			File modulesDir = new File(slcDir, "modules");
208 
209 			// JAAS
210 			// File jaasFile = new File(confDir, "jaas.config");
211 			// if (!jaasFile.exists())
212 			// copyResource("/org/argeo/slc/cli/jaas.config", jaasFile);
213 			// System.setProperty("java.security.auth.login.config",
214 			// jaasFile.getCanonicalPath());
215 
216 			// log4j
217 			File log4jFile = new File(confDir, "log4j.properties");
218 			if (!log4jFile.exists())
219 				copyResource("/org/argeo/slc/cli/log4j.properties", log4jFile);
220 			System.setProperty("log4j.configuration", "file://" + log4jFile.getCanonicalPath());
221 			// Run as a privileged action
222 			// LoginContext lc = new LoginContext(os);
223 			// lc.login();
224 			//
225 			// Subject subject =
226 			// Subject.getSubject(AccessController.getContext());
227 			// Subject.doAs(subject, new SlcMain(args, confDir, dataDir,
228 			// modulesDir));
229 			SlcMain slcMain = new SlcMain(args, confDir, dataDir, modulesDir);
230 			slcMain.run();
231 			if (args.length != 0)
232 				System.exit(0);
233 		} catch (Exception e) {
234 			e.printStackTrace();
235 			System.exit(1);
236 		}
237 	}
238 
239 	/**
240 	 * Recursively look in parent directories for a directory named
241 	 * {@link #slcDirName}
242 	 */
243 	protected static File findSlcDir(File currentDir) {
244 		File slcDir = new File(currentDir, slcDirName);
245 		// covers the use case of running from the home directory
246 		if (slcDir.exists() && slcDir.isDirectory())
247 			return slcDir;
248 		File parentDir = currentDir.getParentFile();
249 		if (parentDir == null)
250 			return null;
251 		try {
252 			// ~/.slc reserved for agent
253 			if (parentDir.getCanonicalPath().equals(homeDir.getCanonicalPath()))
254 				return null;
255 		} catch (IOException e) {
256 			throw new RuntimeException("Cannot check home directory", e);
257 		}
258 		return findSlcDir(parentDir);
259 	}
260 
261 	protected static void copyResource(String resource, File targetFile) {
262 		InputStream input = null;
263 		FileOutputStream output = null;
264 		try {
265 			input = SlcMain.class.getResourceAsStream(resource);
266 			output = new FileOutputStream(targetFile);
267 			byte[] buf = new byte[8192];
268 			while (true) {
269 				int length = input.read(buf);
270 				if (length < 0)
271 					break;
272 				output.write(buf, 0, length);
273 			}
274 		} catch (Exception e) {
275 			throw new RuntimeException("Cannot write " + resource + " file to " + targetFile, e);
276 		} finally {
277 			try {
278 				input.close();
279 			} catch (Exception ignore) {
280 			}
281 			try {
282 				output.close();
283 			} catch (Exception ignore) {
284 			}
285 		}
286 
287 	}
288 
289 	protected static void info(Object msg) {
290 		System.out.println(msg);
291 	}
292 
293 	protected static void err(Object msg) {
294 		System.err.println(msg);
295 	}
296 
297 	protected static void debug(Object msg) {
298 		System.out.println(msg);
299 	}
300 
301 }
302 
303 // private String bundlesToInstall = System.getProperty("user.home")
304 // +
305 // "/dev/src/slc/dep/org.argeo.slc.dep.minimal/target/dependency;in=*.jar,"
306 // + System.getProperty("user.home")
307 // + "/dev/src/slc/demo/modules;in=*;ex=pom.xml;ex=.svn";
308 
309 // ServiceTracker agentTracker = new ServiceTracker(bundleContext,
310 // "org.argeo.slc.execution.SlcAgentCli", null);
311 // agentTracker.open();
312 // final Object agentCli = agentTracker.waitForService(30 * 1000);
313 // if (agentCli == null)
314 // throw new RuntimeException("Cannot find SLC agent CLI");
315 
316 // protected class AgentCliCall implements PrivilegedAction<String> {
317 // private final Object agentCli;
318 //
319 // public AgentCliCall(Object agentCli) {
320 // super();
321 // this.agentCli = agentCli;
322 // }
323 //
324 // public String run() {
325 // try {
326 // Class<?>[] parameterTypes = { String[].class };
327 // Method method = agentCli.getClass().getMethod("process",
328 // parameterTypes);
329 // Object[] methodArgs = { args };
330 // Object ret = method.invoke(agentCli, methodArgs);
331 // return ret.toString();
332 // } catch (Exception e) {
333 // throw new RuntimeException("Cannot run "
334 // + Arrays.toString(args) + " on " + agentCli, e);
335 // }
336 // }
337 //
338 // }