/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nuxeo - initial API and implementation * * $Id$ */ package org.eclipse.ecr.runtime.api; import java.io.File; import java.net.URL; import java.util.Properties; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import org.apache.commons.io.FileCleaningTracker; import org.apache.commons.io.FileDeleteStrategy; import org.eclipse.ecr.runtime.RuntimeService; import org.eclipse.ecr.runtime.RuntimeServiceEvent; import org.eclipse.ecr.runtime.RuntimeServiceListener; import org.eclipse.ecr.runtime.ServiceManager; import org.eclipse.ecr.runtime.api.login.LoginAs; import org.eclipse.ecr.runtime.api.login.LoginService; import org.nuxeo.common.Environment; import org.nuxeo.common.collections.ListenerList; /** * This class is the main entry point to a Nuxeo runtime application. * <p> * It offers an easy way to create new sessions, to access system services and * other resources. * <p> * There are two type of services: * <ul> * <li>Global Services - these services are uniquely defined by a service class, * and there is an unique instance of the service in the system per class. * <li>Local Services - these services are defined by a class and an URI. This * type of service allows multiple service instances for the same class of * services. Each instance is uniquely defined in the system by an URI. * </ul> * * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ public final class Framework { /** * The runtime instance. */ private static RuntimeService runtime; private static ServiceManager serviceMgr; private static final ListenerList listeners = new ListenerList(); private static final FileCleaningTracker fileCleaningTracker = new FileCleaningTracker(); /** * A class loader used to share resources between all bundles. * <p> * This is useful to put resources outside any bundle (in a directory on the * file system) and then refer them from XML contributions. * <p> * The resource directory used by this loader is ${nuxeo_data_dir}/resources * whee ${nuxeo_data_dir} is usually ${nuxeo_home}/data */ protected static SharedResourceLoader resourceLoader; /** * Whether or not services should be exported as OSGI services. This is * controlled by the ${ecr.osgi.services} property. The default is false. */ protected static Boolean isOSGiServiceSupported; // Utility class. private Framework() { } // FIXME: this method can't work as it is implemented here. public static void initialize(RuntimeService runtimeService) throws Exception { if (runtime != null) { throw new Exception("Nuxeo Framework was already initialized"); } runtime = runtimeService; reloadResourceLoader(); initServiceManager(); runtime.start(); } public static void reloadResourceLoader() throws Exception { File rs = new File(Environment.getDefault().getData(), "resources"); rs.mkdirs(); resourceLoader = new SharedResourceLoader(new URL[] { rs.toURI() .toURL() }, Framework.class.getClassLoader()); } public static void shutdown() throws Exception { if (runtime != null) { runtime.stop(); runtime = null; } } /** * Tests whether or not the runtime was initialized. * * @return true if the runtime was initialized, false otherwise */ public static synchronized boolean isInitialized() { return runtime != null; } public static SharedResourceLoader getResourceLoader() { return resourceLoader; } private static void initServiceManager() { serviceMgr = org.eclipse.ecr.runtime.api.ServiceManager.getInstance(); } /** * Gets the runtime service instance. * * @return the runtime service instance */ public static RuntimeService getRuntime() { return runtime; } /** * Gets a service given its class. */ public static <T> T getService(Class<T> serviceClass) throws Exception { return serviceMgr.getService(serviceClass); } /** * Gets a service given its class and an identifier. */ public static <T> T getService(Class<T> serviceClass, String name) throws Exception { return serviceMgr.getService(serviceClass, name); } /** * Gets a nuxeo-runtime local service. */ public static <T> T getLocalService(Class<T> serviceClass) { ServiceProvider provider = DefaultServiceProvider.getProvider(); if (provider != null) { return provider.getService(serviceClass); } // TODO impl a runtime service provider return runtime.getService(serviceClass); } /** * Lookup a registered object given its key. */ public static Object lookup(String key) { return null; // TODO } /** * Login in the system as the system user (a pseudo-user having all * privileges). * * @return the login session if successful. Never returns null. * @throws LoginException * on login failure */ public static LoginContext login() throws LoginException { if (null == runtime) { throw new IllegalStateException("runtime not initialized"); } LoginService loginService = runtime.getService(LoginService.class); if (loginService != null) { return loginService.login(); } return null; } /** * Login in the system as the system user (a pseudo-user having all * privileges). The given username will be used to identify the user id that * called this method. * * @param username * the originating user id * @return the login session if successful. Never returns null. * @throws LoginException * on login failure */ public static LoginContext loginAs(String username) throws LoginException { if (null == runtime) { throw new IllegalStateException("runtime not initialized"); } LoginService loginService = runtime.getService(LoginService.class); if (loginService != null) { return loginService.loginAs(username); } return null; } /** * Login in the system as the given user without checking the password. * * @param username * the user name to login as. * @return the login context * @throws LoginException * if any error occurs * * @since 5.4.2 */ public static LoginContext loginAsUser(String username) throws LoginException { return getLocalService(LoginAs.class).loginAs(username); } /** * Login in the system as the given user using the given password. * * @param username * the username to login * @param password * the password * @return a login session if login was successful. Never returns null. * @throws LoginException * if login failed */ public static LoginContext login(String username, Object password) throws LoginException { LoginService loginService = runtime.getService(LoginService.class); if (loginService != null) { return loginService.login(username, password); } return null; } /** * Login in the system using the given callback handler for login info * resolution. * * @param cbHandler * used to fetch the login info * @return the login context * @throws LoginException */ public static LoginContext login(CallbackHandler cbHandler) throws LoginException { LoginService loginService = runtime.getService(LoginService.class); if (loginService != null) { return loginService.login(cbHandler); } return null; } public static void sendEvent(RuntimeServiceEvent event) { Object[] listenersArray = listeners.getListeners(); for (Object listener : listenersArray) { ((RuntimeServiceListener) listener).handleEvent(event); } } /** * Registers a listener to be notified about runtime events. * <p> * If the listener is already registered, do nothing. * * @param listener * the listener to register */ public static void addListener(RuntimeServiceListener listener) { listeners.add(listener); } /** * Removes the given listener. * <p> * If the listener is not registered, do nothing. * * @param listener * the listener to remove */ public static void removeListener(RuntimeServiceListener listener) { listeners.remove(listener); } /** * Gets the given property value if any, otherwise null. * <p> * The framework properties will be searched first then if any matching * property is found the system properties are searched too. * * @param key * the property key * @return the property value if any or null otherwise */ public static String getProperty(String key) { return getProperty(key, null); } /** * Gets the given property value if any, otherwise returns the given default * value. * <p> * The framework properties will be searched first then if any matching * property is found the system properties are searched too. * * @param key * the property key * @param defValue * the default value to use * @return the property value if any otherwise the default value */ public static String getProperty(String key, String defValue) { return runtime.getProperty(key, defValue); } /** * Gets all the framework properties. The system properties are not included * in the returned map. * * @return the framework properties map. Never returns null. */ public static Properties getProperties() { return runtime.getProperties(); } /** * Expands any variable found in the given expression with the value of the * corresponding framework property. * <p> * The variable format is ${property_key}. * <p> * System properties are also expanded. */ public static String expandVars(String expression) { int p = expression.indexOf("${"); if (p == -1) { return expression; // do not expand if not needed } char[] buf = expression.toCharArray(); StringBuilder result = new StringBuilder(buf.length); if (p > 0) { result.append(expression.substring(0, p)); } StringBuilder varBuf = new StringBuilder(); boolean dollar = false; boolean var = false; for (int i = p; i < buf.length; i++) { char c = buf[i]; switch (c) { case '$': dollar = true; break; case '{': if (dollar) { dollar = false; var = true; } else { result.append(c); } break; case '}': if (var) { var = false; String varName = varBuf.toString(); varBuf.setLength(0); String varValue = getProperty(varName); // get the variable // value if (varValue != null) { result.append(varValue); } else { // let the variable as is result.append("${").append(varName).append('}'); } } else { result.append(c); } break; default: if (var) { varBuf.append(c); } else { result.append(c); } break; } } return result.toString(); } public static boolean isOSGiServiceSupported() { if (isOSGiServiceSupported == null) { isOSGiServiceSupported = Boolean.valueOf(getProperty( "ecr.osgi.services", "false")); } return isOSGiServiceSupported; } public static boolean isDevModeSet() { String dev = getProperty("org.nuxeo.dev"); if (dev == null) { dev = System.getProperty("org.nuxeo.dev"); } return dev != null && !dev.equals("false"); } public static boolean isTestModeSet() { String test = getProperty("org.eclipse.ecr.runtime.testing"); if (test == null) { test = System.getProperty("org.eclipse.ecr.runtime.testing"); } return test != null && !test.equals("false"); } /** * This method stops the application if development mode is enabled (i.e. * org.nuxeo.dev system property is set) and one of the following errors * occurs during startup: * <ul> * <li>Component XML parse error. * <li>Contribution to an unknown extension point. * <li>Component with an unknown implementation class (the implementation * entry exists in the XML descriptor but cannot be resolved to a class). * <li>Uncatched exception on extension registration / unregistration * (either in framework or user component code) * <li>Uncatched exception on component activation / decativation (either in * framework or user component code) * <li>Broken Nuxeo-Component MANIFEST entry. (i.e. the entry cannot be * resolved to a resource) * </ul> * * @param t * the exception or null if none */ public static void handleDevError(Throwable t) { if (isDevModeSet()) { System.err.println("Fatal error caught in dev. mode: exiting."); t.printStackTrace(); System.exit(1); } } /** * Deletes the given file when the marker object is collected by GC. * * @param file * The file to delete * @param marker * the marker Object */ public static void trackFile(File file, Object marker) { fileCleaningTracker.track(file, marker); } /** * Deletes the given file when the marker object is collected by GC. The * fileDeleteStrategy can be used for instance do delete only empty * directory or force deletion. * * @param file * The file to delete * @param marker * the marker Object * @param fileDeleteStrategy * add a custom delete strategy */ public static void trackFile(File file, Object marker, FileDeleteStrategy fileDeleteStrategy) { fileCleaningTracker.track(file, marker, fileDeleteStrategy); } public static void main(String[] args) { } }