/* * Copyright (C) 2003-2011 eXo Platform SAS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.etk.component.base.naming; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Collection; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NameAlreadyBoundException; import javax.naming.NamingException; import javax.naming.Reference; import javax.xml.stream.XMLStreamException; import org.etk.common.utils.PrivilegedSystemHelper; import org.etk.common.utils.SystemHelper; import org.etk.common.logging.Logger; import org.etk.kernel.container.component.ComponentPlugin; import org.etk.kernel.container.configuration.ConfigurationException; import org.etk.kernel.container.xml.InitParams; import org.etk.kernel.container.xml.PropertiesParam; import org.etk.kernel.container.xml.Property; import org.etk.kernel.container.xml.ValueParam; /** * Created by The eXo Platform SAS * Author : eXoPlatform * thanhvucong.78@google.com * Aug 6, 2011 */ public class InitialContextInitializer { static String DEFAULT_INITIAL_CONTEXT_FACTORY = PrivilegedSystemHelper.getProperty(Context.INITIAL_CONTEXT_FACTORY); public static final String PROPERTIES_DEFAULT = "default-properties"; public static final String PROPERTIES_MANDATORY = "mandatory-properties"; /** * This parameter is used to overload the default initial context factory in order to ensure that binded objects are shared */ public static final String OVERLOAD_CONTEXT_FACTORY = "overload-context-factory"; public static final String BINDINGS_STORE_PATH = "bindings-store-path"; public static final String DEFAULT_BINDING_STORE_PATH = PrivilegedSystemHelper.getProperty("java.io.tmpdir") + File.separator + "bind-references.xml"; private static Logger LOG = Logger.getLogger(InitialContextInitializer.class); private List<BindReferencePlugin> bindReferencesPlugins; private final InitialContextBinder binder; /** * @param params * @throws NamingException * @throws ConfigurationException if no context factory initialized and no * context-factory nor default-context-factory configured * @throws XMLStreamException if error of serialized bindings read * @throws FileNotFoundException if cannot open file with serialized bindings */ public InitialContextInitializer(InitParams params) throws NamingException, ConfigurationException, FileNotFoundException, XMLStreamException { for (Iterator propsParams = params.getPropertiesParamIterator(); propsParams.hasNext();) { PropertiesParam propParam = (PropertiesParam)propsParams.next(); boolean isDefault = propParam.getName().equals(PROPERTIES_DEFAULT); boolean isMandatory = propParam.getName().equals(PROPERTIES_MANDATORY); for (Iterator props = propParam.getPropertyIterator(); props.hasNext();) { Property prop = (Property)props.next(); String propName = prop.getName(); String propValue = prop.getValue(); String existedProp = PrivilegedSystemHelper.getProperty(propName); if (isMandatory) { setSystemProperty(propName, propValue, propParam.getName()); } else if (isDefault) { if (existedProp == null) { setSystemProperty(propName, propValue, propParam.getName()); } else { LOG.info("Using default system property: " + propName + " = " + existedProp); } } } } bindReferencesPlugins = new ArrayList<BindReferencePlugin>(); ValueParam bindingStorePathParam = params.getValueParam(BINDINGS_STORE_PATH); if (LOG.isDebugEnabled()) { LOG.debug("The default initial context factory is " + DEFAULT_INITIAL_CONTEXT_FACTORY); } ValueParam overloadContextFactoryParam = params.getValueParam(OVERLOAD_CONTEXT_FACTORY); if (overloadContextFactoryParam != null && overloadContextFactoryParam.getValue() != null && Boolean.valueOf(overloadContextFactoryParam.getValue())) { PrivilegedSystemHelper.setProperty(Context.INITIAL_CONTEXT_FACTORY, ExoContainerContextFactory.class.getName()); } // binder if (bindingStorePathParam == null) { binder = new InitialContextBinder(this, DEFAULT_BINDING_STORE_PATH); } else { binder = new InitialContextBinder(this, bindingStorePathParam.getValue()); } } private void setSystemProperty(String propName, String propValue, String propParamName) { PrivilegedSystemHelper.setProperty(propName, propValue); if (propName.equals(Context.INITIAL_CONTEXT_FACTORY)) { DEFAULT_INITIAL_CONTEXT_FACTORY = PrivilegedSystemHelper.getProperty(Context.INITIAL_CONTEXT_FACTORY); } LOG.info("Using mandatory system property: " + propName + " = " + PrivilegedSystemHelper.getProperty(propName)); } // for out-of-container testing private InitialContextInitializer(String name, Reference reference) throws NamingException, FileNotFoundException, XMLStreamException { PrivilegedSystemHelper.setProperty(Context.INITIAL_CONTEXT_FACTORY, DEFAULT_INITIAL_CONTEXT_FACTORY); InitialContext initialContext = getInitialContext(); initialContext.rebind(name, reference); // binder binder = new InitialContextBinder(this, DEFAULT_BINDING_STORE_PATH); } /** * Patch for case when bound objects are not shared i.e. there are some parts * of app using different copy of Context, for example per web app * InitialContext in Tomcat */ @Deprecated public void recall() { for (BindReferencePlugin plugin : bindReferencesPlugins) { try { InitialContext ic = getInitialContext(); ic.bind(plugin.getBindName(), plugin.getReference()); LOG.info("Reference bound (by recall()): " + plugin.getBindName()); } catch (NameAlreadyBoundException e) { LOG.debug("Name already bound: " + plugin.getBindName()); } catch (NamingException e) { LOG.error("Could not bind: " + plugin.getBindName(), e); } } } public void addPlugin(ComponentPlugin plugin) { if (plugin instanceof BindReferencePlugin) { BindReferencePlugin brplugin = (BindReferencePlugin)plugin; try { InitialContext ic = getInitialContext(); ic.rebind(brplugin.getBindName(), brplugin.getReference()); LOG.info("Reference bound: " + brplugin.getBindName()); bindReferencesPlugins.add((BindReferencePlugin)plugin); } catch (NamingException e) { LOG.error("Could not bind: " + brplugin.getBindName(), e); } } } public ComponentPlugin removePlugin(String name) { return null; } public Collection getPlugins() { return bindReferencesPlugins; } /** * @return defaultContextFactory name */ public String getDefaultContextFactory() { return DEFAULT_INITIAL_CONTEXT_FACTORY; } /** * @return stored InitialContext */ public InitialContext getInitialContext() { try { Hashtable<String, Object> env = new Hashtable<String, Object>(); env.put(InitialContextInitializer.class.getName(), "true"); return new InitialContext(env); } catch (NamingException e) { throw new RuntimeException("Cannot create the intial context", e); } } // for out-of-container testing public static void initialize(String name, Reference reference) throws NamingException, FileNotFoundException, XMLStreamException { new InitialContextInitializer(name, reference); } /** * Returns InitialContextBinder. */ public InitialContextBinder getInitialContextBinder() { return binder; } }