001/* 002 * (C) Copyright 2006-2017 Nuxeo (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 */ 019package org.nuxeo.runtime.model.impl; 020 021import java.io.ByteArrayInputStream; 022import java.io.IOException; 023import java.io.InputStream; 024import java.net.URL; 025import java.util.ArrayList; 026import java.util.List; 027 028import org.apache.commons.codec.Charsets; 029import org.apache.commons.io.IOUtils; 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032import org.nuxeo.runtime.RuntimeService; 033import org.nuxeo.runtime.RuntimeServiceException; 034import org.nuxeo.runtime.api.Framework; 035import org.nuxeo.runtime.model.ComponentManager; 036import org.nuxeo.runtime.model.ComponentName; 037import org.nuxeo.runtime.model.RegistrationInfo; 038import org.nuxeo.runtime.model.RuntimeContext; 039import org.nuxeo.runtime.model.StreamRef; 040import org.nuxeo.runtime.model.URLStreamRef; 041import org.nuxeo.runtime.osgi.OSGiRuntimeActivator; 042import org.nuxeo.runtime.osgi.OSGiRuntimeContext; 043import org.osgi.framework.Bundle; 044 045/** 046 * New behavior @since 9.2 As the runtime lifecycle changed there make no sense to unregister components by their own. 047 * <p /> 048 * The component registry is either reset to a clean state or shutdown. 049 * <p /> 050 * So methods like unregister by location used in tests make no sense. These methods are preserved yet for compatibility 051 * with some tests but may be removed in future. 052 * <p /> 053 * Also when a context is destroyed we unregister all the components the context deployed. 054 * <p /> 055 * This is also deprecated since the unregister component is deprecated too. 056 * <p /> 057 * The code inside destroy method was removed too since the deployedFiles map was removed. 058 * <p /> 059 * This map posed problems with the registry snapshot approaches since it was not kept in sync with the registry. 060 * <p /> 061 * <p /> 062 * If unregistering components will be removed completely don't forget to remove 063 * {@link ComponentManager#unregisterByLocation(String)} and the {@link ComponentRegistry#deployedFiles}. 064 * <p /> 065 * <p /> 066 * Features like studio or IDE which needs unregistering components must use their own mechanism. 067 * 068 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 069 */ 070public class DefaultRuntimeContext implements RuntimeContext { 071 072 private static final Log log = LogFactory.getLog(RuntimeContext.class); 073 074 protected RuntimeService runtime; 075 076 /** 077 * The list of component names deployed by this context. 078 * 079 * @since 9.2 080 */ 081 protected List<ComponentName> components; 082 083 protected final ComponentDescriptorReader reader; 084 085 public DefaultRuntimeContext() { 086 this(Framework.getRuntime()); 087 } 088 089 public DefaultRuntimeContext(RuntimeService runtime) { 090 this.runtime = runtime; 091 this.components = new ArrayList<>(); 092 reader = new ComponentDescriptorReader(); 093 } 094 095 public void setRuntime(RuntimeService runtime) { 096 this.runtime = runtime; 097 } 098 099 @Override 100 public RuntimeService getRuntime() { 101 return runtime; 102 } 103 104 @Override 105 public ComponentName[] getComponents() { 106 return components.toArray(new ComponentName[components.size()]); 107 } 108 109 @Override 110 public URL getResource(String name) { 111 return Thread.currentThread().getContextClassLoader().getResource(name); 112 } 113 114 @Override 115 public URL getLocalResource(String name) { 116 return Thread.currentThread().getContextClassLoader().getResource(name); 117 } 118 119 @Override 120 public Class<?> loadClass(String className) throws ClassNotFoundException { 121 return Thread.currentThread().getContextClassLoader().loadClass(className); 122 } 123 124 @Override 125 public RegistrationInfo deploy(URL url) throws IOException { 126 return deploy(new URLStreamRef(url)); 127 } 128 129 @Override 130 public RegistrationInfo deploy(StreamRef ref) throws IOException { 131 String name = ref.getId(); 132 RegistrationInfoImpl ri = createRegistrationInfo(ref); 133 if (ri == null || ri.name == null) { 134 // not parsed correctly, e.g., faces-config.xml 135 return null; 136 } 137 log.debug("Deploying component from url " + name); 138 ri.sourceId = name; 139 ri.context = this; 140 ri.xmlFileUrl = ref.asURL(); 141 if (ri.getBundle() != null) { 142 // this is an external component XML. 143 // should use the real owner bundle as the context. 144 Bundle bundle = OSGiRuntimeActivator.getInstance().getBundle(ri.getBundle()); 145 if (bundle != null) { 146 ri.context = new OSGiRuntimeContext(bundle); 147 } 148 } 149 runtime.getComponentManager().register(ri); 150 components.add(ri.name); 151 return ri; 152 } 153 154 @Override 155 public void undeploy(URL url) { 156 runtime.getComponentManager().unregisterByLocation(url.toString()); 157 } 158 159 @Override 160 public void undeploy(StreamRef ref) { 161 runtime.getComponentManager().unregisterByLocation(ref.getId()); 162 } 163 164 @Override 165 public boolean isDeployed(URL url) { 166 return runtime.getComponentManager().hasComponentFromLocation(url.toString()); 167 } 168 169 @Override 170 public boolean isDeployed(StreamRef ref) { 171 return runtime.getComponentManager().hasComponentFromLocation(ref.getId()); 172 } 173 174 @Override 175 public RegistrationInfo deploy(String location) { 176 URL url = getLocalResource(location); 177 if (url == null) { 178 throw new IllegalArgumentException("No local resources was found with this name: " + location); 179 } 180 try { 181 return deploy(url); 182 } catch (IOException e) { 183 throw new RuntimeServiceException("Cannot deploy: " + location, e); 184 } 185 } 186 187 @Override 188 public void undeploy(String location) { 189 URL url = getLocalResource(location); 190 if (url == null) { 191 throw new IllegalArgumentException("No local resources was found with this name: " + location); 192 } 193 undeploy(url); 194 } 195 196 @Override 197 public boolean isDeployed(String location) { 198 URL url = getLocalResource(location); 199 if (url != null) { 200 return isDeployed(url); 201 } else { 202 log.warn("No local resources was found with this name: " + location); 203 return false; 204 } 205 } 206 207 @Override 208 public void destroy() { 209 ComponentManager mgr = runtime.getComponentManager(); 210 for (ComponentName cname : components) { 211 mgr.unregister(cname); 212 } 213 } 214 215 @Override 216 public Bundle getBundle() { 217 return null; 218 } 219 220 public RegistrationInfoImpl createRegistrationInfo(StreamRef ref) throws IOException { 221 String source = IOUtils.toString(ref.getStream(), Charsets.UTF_8); 222 String expanded = Framework.expandVars(source); 223 try (InputStream in = new ByteArrayInputStream(expanded.getBytes())) { 224 return createRegistrationInfo(in); 225 } 226 } 227 228 public RegistrationInfoImpl createRegistrationInfo(InputStream in) throws IOException { 229 return reader.read(this, in); 230 } 231 232}