/* * 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.model.impl; import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.ecr.runtime.ComponentEvent; import org.eclipse.ecr.runtime.Version; import org.eclipse.ecr.runtime.api.Framework; import org.eclipse.ecr.runtime.model.Component; import org.eclipse.ecr.runtime.model.ComponentInstance; import org.eclipse.ecr.runtime.model.ComponentManager; import org.eclipse.ecr.runtime.model.ComponentName; import org.eclipse.ecr.runtime.model.ConfigurationDescriptor; import org.eclipse.ecr.runtime.model.Extension; import org.eclipse.ecr.runtime.model.ExtensionPoint; import org.eclipse.ecr.runtime.model.Property; import org.eclipse.ecr.runtime.model.RegistrationInfo; import org.eclipse.ecr.runtime.model.RuntimeContext; import org.nuxeo.common.xmap.annotation.XContent; import org.nuxeo.common.xmap.annotation.XNode; import org.nuxeo.common.xmap.annotation.XNodeList; import org.nuxeo.common.xmap.annotation.XNodeMap; import org.nuxeo.common.xmap.annotation.XObject; /** * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> * */ @XObject("component") public class RegistrationInfoImpl implements RegistrationInfo { private static final long serialVersionUID = -4135715215018199522L; private static final Log log = LogFactory.getLog(RegistrationInfoImpl.class); // Note: some of these instance variables are accessed directly from other // classes in this package. transient ComponentManagerImpl manager; @XNode("@service") ServiceDescriptor serviceDescriptor; // the managed object name @XNode("@name") ComponentName name; @XNode("@disabled") boolean disabled; @XNode("configuration") ConfigurationDescriptor config; // the registration state int state = UNREGISTERED; // the object names I depend of @XNodeList(value = "require", type = HashSet.class, componentType = ComponentName.class) Set<ComponentName> requires; // the object names I depend of and that are blocking my registration Set<ComponentName> waitsFor; // registration that depends on me Set<RegistrationInfoImpl> dependsOnMe; @XNode("implementation@class") String implementation; @XNodeList(value = "extension-point", type = ExtensionPointImpl[].class, componentType = ExtensionPointImpl.class) ExtensionPointImpl[] extensionPoints; @XNodeList(value = "extension", type = ExtensionImpl[].class, componentType = ExtensionImpl.class) ExtensionImpl[] extensions; @XNodeMap(value = "property", key = "@name", type = HashMap.class, componentType = Property.class) Map<String, Property> properties; @XNode("@version") Version version = Version.ZERO; /** * To be set when deploying configuration components that are not in a * bundle (e.g. from config. dir). * * Represent the bundle that will be assumed to be the owner of the * component. */ @XNode("@bundle") String bundle; @XContent("documentation") String documentation; URL xmlFileUrl; /** * This is used by the component persistence service to identify * registration that was dynamically created and persisted by users. */ boolean isPersistent; transient RuntimeContext context; // the managed component transient ComponentInstance component; public RegistrationInfoImpl() { } /** * Useful when dynamically registering components * * @param name the component name */ public RegistrationInfoImpl(ComponentName name) { this.name = name; } public void setContext(RuntimeContext rc) { this.context = rc; } @Override public boolean isDisabled() { return disabled; } public Set<RegistrationInfoImpl> getDependsOnMe() { return dependsOnMe; } public Set<ComponentName> getWaitsFor() { return waitsFor; } @Override public final boolean isPersistent() { return isPersistent; } @Override public void setPersistent(boolean isPersistent) { this.isPersistent = isPersistent; } public final boolean isPending() { return waitsFor != null; } public void destroy() { if (waitsFor != null) { waitsFor.clear(); waitsFor = null; } if (requires != null) { requires.clear(); requires = null; } if (dependsOnMe != null) { dependsOnMe.clear(); dependsOnMe = null; } component = null; name = null; manager = null; } public final boolean isDisposed() { return name == null; } @Override public ExtensionPoint[] getExtensionPoints() { return extensionPoints; } @Override public ComponentInstance getComponent() { return component; } /** * Reload the underlying component if reload is supported * @throws Exception */ public synchronized void reload() throws Exception { if (component != null) { component.reload(); } } @Override public ComponentName getName() { return name; } @Override public Map<String, Property> getProperties() { return properties; } public ExtensionPointImpl getExtensionPoint(String name) { for (ExtensionPointImpl xp : extensionPoints) { if (xp.name.equals(name)) { return xp; } } return null; } @Override public int getState() { return state; } @Override public Extension[] getExtensions() { return extensions; } @Override public Set<ComponentName> getRequiredComponents() { return requires; } @Override public RuntimeContext getContext() { return context; } @Override public String getBundle() { return bundle; } @Override public Version getVersion() { return version; } @Override public String getDocumentation() { return documentation; } @Override public String toString() { return "RegistrationInfo: " + name; } @Override public ComponentManager getManager() { return manager; } synchronized void register() { if (state != UNREGISTERED) { return; } state = REGISTERED; manager.sendEvent(new ComponentEvent( ComponentEvent.COMPONENT_REGISTERED, this)); } synchronized void unregister() throws Exception { if (state == UNREGISTERED) { return; } if (state == ACTIVATED || state == RESOLVED) { unresolve(); } state = UNREGISTERED; manager.sendEvent(new ComponentEvent( ComponentEvent.COMPONENT_UNREGISTERED, this)); destroy(); } protected ComponentInstance createComponentInstance() throws Exception { try { return new ComponentInstanceImpl(this); } catch (Exception e) { String msg = "Failed to instantiate component: " + implementation; log.error(msg, e); msg += " (" + e.toString() + ')'; Framework.getRuntime().getWarnings().add(msg); Framework.handleDevError(e); throw e; } } public synchronized void restart() throws Exception { deactivate(); activate(); } @Override public void notifyApplicationStarted() throws Exception { if (component != null) { Object ci = component.getInstance(); if (ci instanceof Component) { ((Component) ci).applicationStarted(component); } } } public synchronized void activate() throws Exception { if (state != RESOLVED) { return; } component = createComponentInstance(); state = ACTIVATING; manager.sendEvent(new ComponentEvent( ComponentEvent.ACTIVATING_COMPONENT, this)); // activate component component.activate(); state = ACTIVATED; manager.sendEvent(new ComponentEvent( ComponentEvent.COMPONENT_ACTIVATED, this)); // register contributed extensions if any if (extensions != null) { checkExtensions(); for (Extension xt : extensions) { xt.setComponent(component); try { manager.registerExtension(xt); } catch (Exception e) { String msg = "Failed to register extension to: " + xt.getTargetComponent() + ", xpoint: " + xt.getExtensionPoint() + " in component: " + xt.getComponent().getName(); log.error(msg, e); msg += " (" + e.toString() + ')'; Framework.getRuntime().getWarnings().add(msg); Framework.handleDevError(e); } } } // register pending extensions if any ComponentManagerImpl mgr = manager; Set<Extension> pendingExt = mgr.pendingExtensions.remove(name); if (pendingExt != null) { for (Extension xt : pendingExt) { ComponentManagerImpl.loadContributions(this, xt); try { component.registerExtension(xt); } catch (Exception e) { String msg = "Failed to register extension to: " + xt.getTargetComponent() + ", xpoint: " + xt.getExtensionPoint() + " in component: " + xt.getComponent().getName(); log.error(msg, e); msg += " (" + e.toString() + ')'; Framework.getRuntime().getWarnings().add(msg); Framework.handleDevError(e); } } } } public synchronized void deactivate() throws Exception { if (state != ACTIVATED) { return; } state = DEACTIVATING; manager.sendEvent(new ComponentEvent( ComponentEvent.DEACTIVATING_COMPONENT, this)); // unregister contributed extensions if any if (extensions != null) { for (Extension xt : extensions) { try { manager.unregisterExtension(xt); } catch (Exception e) { log.error( "Failed to unregister extension. Contributor: " + xt.getComponent() + " to " + xt.getTargetComponent() + "; xpoint: " + xt.getExtensionPoint(), e); Framework.handleDevError(e); } } } component.deactivate(); component = null; state = RESOLVED; manager.sendEvent(new ComponentEvent( ComponentEvent.COMPONENT_DEACTIVATED, this)); } public synchronized void resolve() throws Exception { if (state != REGISTERED) { return; } // register services manager.registerServices(this); state = RESOLVED; manager.sendEvent(new ComponentEvent(ComponentEvent.COMPONENT_RESOLVED, this)); // TODO lazy activation activate(); } public synchronized void unresolve() throws Exception { if (state == REGISTERED || state == UNREGISTERED) { return; } // un-register services manager.unregisterServices(this); if (state == ACTIVATED) { deactivate(); } state = REGISTERED; manager.sendEvent(new ComponentEvent( ComponentEvent.COMPONENT_UNRESOLVED, this)); } @Override public synchronized boolean isActivated() { return state == ACTIVATED; } @Override public synchronized boolean isResolved() { return state == RESOLVED; } @Override public String[] getProvidedServiceNames() { if (serviceDescriptor != null) { return serviceDescriptor.services; } return null; } public ServiceDescriptor getServiceDescriptor() { return serviceDescriptor; } @Override public String getImplementation() { return implementation; } public void checkExtensions() { if (extensions == null) { return; } // HashSet<String> targets = new HashSet<String>(); for (ExtensionImpl xt : extensions) { if (xt.target == null) { Framework.getRuntime().getWarnings().add( "Bad extension declaration (no target attribute specified). Component: " + getName()); continue; } // TODO do nothing for now -> fix the faulty components and then // activate these warnings // String key = xt.target.getName()+"#"+xt.getExtensionPoint(); // if (targets.contains(key)) { // multiple extensions to same // target point declared in same component // String message = // "Component "+getName()+" contains multiple extensions to "+key; // Framework.getRuntime().getWarnings().add(message); // //TODO: un-comment the following line if you want to treat this // as a dev. error // //Framework.handleDevError(new Error(message)); // } else { // targets.add(key); // } } } @Override public URL getXmlFileUrl() { return xmlFileUrl; } }