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