/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.servicemix.jbi.framework;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.jbi.JBIException;
import javax.jbi.component.ServiceUnitManager;
import javax.jbi.management.DeploymentException;
import javax.jbi.management.DeploymentServiceMBean;
import javax.management.JMException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanOperationInfo;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.apache.servicemix.jbi.container.EnvironmentContext;
import org.apache.servicemix.jbi.container.JBIContainer;
import org.apache.servicemix.jbi.container.ServiceAssemblyEnvironment;
import org.apache.servicemix.jbi.deployment.Descriptor;
import org.apache.servicemix.jbi.deployment.DescriptorFactory;
import org.apache.servicemix.jbi.deployment.ServiceAssembly;
import org.apache.servicemix.jbi.deployment.ServiceUnit;
import org.apache.servicemix.jbi.management.AttributeInfoHelper;
import org.apache.servicemix.jbi.management.BaseSystemService;
import org.apache.servicemix.jbi.management.OperationInfoHelper;
import org.apache.servicemix.jbi.management.ParameterHelper;
import org.apache.servicemix.jbi.util.DOMUtil;
import org.apache.servicemix.jbi.util.FileUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The deployment service MBean allows administrative tools to manage service assembly deployments.
*
* @version $Revision: 1186746 $
*/
public class DeploymentService extends BaseSystemService implements DeploymentServiceMBean {
private static final transient Logger LOGGER = LoggerFactory.getLogger(DeploymentService.class);
private EnvironmentContext environmentContext;
private Registry registry;
//
// ServiceMix service implementation
//
/**
* Initialize the Service
*
* @param container
* @throws JBIException
* @throws DeploymentException
*/
public void init(JBIContainer container) throws JBIException {
this.environmentContext = container.getEnvironmentContext();
this.registry = container.getRegistry();
super.init(container);
buildState();
}
protected Class<DeploymentServiceMBean> getServiceMBean() {
return DeploymentServiceMBean.class;
}
public void start() throws JBIException {
super.start();
String[] sas = registry.getDeployedServiceAssemblies();
// This loop will initialize all SAs
container.getBroker().suspend();
for (int j = 0; j < sas.length; j++) {
try {
ServiceAssemblyLifeCycle sa = registry.getServiceAssembly(sas[j]);
sa.init();
} catch (Exception e) {
LOGGER.error("Unable to initialize state for service assembly {}", sas[j], e);
}
}
// This loop will restore SAs
for (int i = 0; i < sas.length; i++) {
try {
ServiceAssemblyLifeCycle sa = registry.getServiceAssembly(sas[i]);
sa.restore(false); // Do not force init SUs
} catch (Exception e) {
LOGGER.error("Unable to restore state for service assembly {}", sas[i], e);
}
}
container.getBroker().resume();
}
/**
* Get an array of MBeanAttributeInfo
*
* @return array of AttributeInfos
* @throws JMException
*/
public MBeanAttributeInfo[] getAttributeInfos() throws JMException {
AttributeInfoHelper helper = new AttributeInfoHelper();
helper.addAttribute(getObjectToManage(), "deployedServiceAssemblies", "list of deployed SAs");
return AttributeInfoHelper.join(super.getAttributeInfos(), helper.getAttributeInfos());
}
/**
* Get an array of MBeanOperationInfo
*
* @return array of OperationInfos
* @throws JMException
*/
public MBeanOperationInfo[] getOperationInfos() throws JMException {
OperationInfoHelper helper = new OperationInfoHelper();
ParameterHelper ph = helper.addOperation(getObjectToManage(), "deploy", 1, "deploy An SA");
ph.setDescription(0, "saZipURL", "location of SA zip file");
ph = helper.addOperation(getObjectToManage(), "undeploy", 1, "undeploy An SA");
ph.setDescription(0, "saName", "SA name");
ph = helper.addOperation(getObjectToManage(), "getDeployedServiceUnitList", 1,
"list of SU's currently deployed");
ph.setDescription(0, "componentName", "Component name");
ph = helper.addOperation(getObjectToManage(), "getServiceAssemblyDescriptor", 1, "Get descriptor for a SA");
ph.setDescription(0, "saName", "SA name");
ph = helper.addOperation(getObjectToManage(), "getDeployedServiceAssembliesForComponent", 1,
"list of SA's for a Component");
ph.setDescription(0, "componentName", "Component name");
ph = helper.addOperation(getObjectToManage(), "getComponentsForDeployedServiceAssembly", 1,
"list of Components for a SA");
ph.setDescription(0, "saName", "SA name");
ph = helper.addOperation(getObjectToManage(), "isDeployedServiceUnit", 2, "is SU deployed at a Component ?");
ph.setDescription(0, "componentName", "Component name");
ph.setDescription(1, "suName", "SU name");
ph = helper
.addOperation(getObjectToManage(), "canDeployToComponent", 1, "Can a SU be deployed to a Component?");
ph.setDescription(0, "componentName", "Component name");
ph = helper.addOperation(getObjectToManage(), "start", 1, "start an SA");
ph.setDescription(0, "saName", "SA name");
ph = helper.addOperation(getObjectToManage(), "stop", 1, "stop an SA");
ph.setDescription(0, "saName", "SA name");
ph = helper.addOperation(getObjectToManage(), "shutDown", 1, "shutDown an SA");
ph.setDescription(0, "saName", "SA name");
ph = helper.addOperation(getObjectToManage(), "getState", 1, "Running state of an SA");
ph.setDescription(0, "saName", "SA name");
return OperationInfoHelper.join(super.getOperationInfos(), helper.getOperationInfos());
}
/**
* Get the description
*
* @return description
*/
public String getDescription() {
return "Allows admin tools to manage service deployments";
}
//
// DeploymentServiceMBean implementation
//
/**
* Deploys the given SA to the JBI environment.
*
* @param saZipURL String containing the location of the Service Assembly zip file.
* @return Result/Status of the SA deployment in xml format.
* @throws Exception in xml format if complete deployment fails.
*/
public String deploy(String saZipURL) throws Exception {
try {
if (saZipURL == null) {
throw ManagementSupport.failure("deploy", "saZipURL must not be null");
}
File tmpDir = null;
try {
tmpDir = AutoDeploymentService.unpackLocation(environmentContext.getTmpDir(), saZipURL);
} catch (Exception e) {
throw ManagementSupport.failure("deploy", "Unable to unpack archive: " + saZipURL, e);
}
// unpackLocation returns null if no jbi descriptor is found
if (tmpDir == null) {
throw ManagementSupport.failure("deploy", "Unable to find jbi descriptor: " + saZipURL);
}
Descriptor root = null;
try {
root = DescriptorFactory.buildDescriptor(tmpDir);
} catch (Exception e) {
throw ManagementSupport.failure("deploy", "Unable to build jbi descriptor: " + saZipURL, e);
}
if (root == null) {
throw ManagementSupport.failure("deploy", "Unable to find jbi descriptor: " + saZipURL);
}
ServiceAssembly sa = root.getServiceAssembly();
if (sa == null) {
throw ManagementSupport.failure("deploy", "JBI descriptor is not an assembly descriptor: " + saZipURL);
}
return deployServiceAssembly(tmpDir, sa);
} catch (Exception e) {
LOGGER.error("Error deploying service assembly", e);
throw e;
}
}
/**
* Undeploys the given SA from the JBI environment.
*
* @param saName name of the SA that has to be undeployed.
* @return Result/Status of the SA undeployment.
* @throws Exception if compelete undeployment fails.
*/
public String undeploy(String saName) throws Exception {
if (saName == null) {
throw ManagementSupport.failure("undeploy", "SA name must not be null");
}
ServiceAssemblyLifeCycle sa = registry.getServiceAssembly(saName);
if (sa == null) {
throw ManagementSupport.failure("undeploy", "SA has not been deployed: " + saName);
}
String state = sa.getCurrentState();
if (!DeploymentServiceMBean.SHUTDOWN.equals(state)) {
throw ManagementSupport.failure("undeploy", "SA must be shut down: " + saName);
}
try {
// Make sure the all service units in the assembly are shutdown.
// SUs can have different states (if a previous shutdown failed).
try {
sa.shutDown();
} catch (Exception e) {
// Ignore
}
String result = null;
String assemblyName = sa.getName();
registry.unregisterServiceAssembly(assemblyName);
ServiceUnitLifeCycle[] sus = sa.getDeployedSUs();
if (sus != null) {
for (int i = 0; i < sus.length; i++) {
undeployServiceUnit(sus[i]);
}
}
FileUtil.deleteFile(sa.getEnvironment().getRootDir());
return result;
} catch (Exception e) {
LOGGER.error("Unable to undeploy assembly", e);
throw e;
}
}
/**
* Returns a list of Service Units that are currently deployed to the given component.
*
* @param componentName name of the component.
* @return List of deployed ASA Ids.
*/
public String[] getDeployedServiceUnitList(String componentName) throws Exception {
try {
ServiceUnitLifeCycle[] sus = registry.getDeployedServiceUnits(componentName);
String[] names = new String[sus.length];
for (int i = 0; i < names.length; i++) {
names[i] = sus[i].getName();
}
return names;
} catch (Exception e) {
LOGGER.info("Unable to get deployed service unit list", e);
throw e;
}
}
/**
* Returns a list of Service Assemblies deployed to the JBI enviroment.
*
* @return list of Service Assembly Name's.
*/
public String[] getDeployedServiceAssemblies() throws Exception {
try {
return registry.getDeployedServiceAssemblies();
} catch (Exception e) {
LOGGER.info("Unable to get deployed service assemblies", e);
throw e;
}
}
/**
* Returns the descriptor of the Service Assembly that was deployed to the JBI enviroment.
*
* @param saName name of the service assembly.
* @return descriptor of the Service Assembly.
*/
public String getServiceAssemblyDescriptor(String saName) throws Exception {
ServiceAssemblyLifeCycle sa = registry.getServiceAssembly(saName);
if (sa != null) {
return sa.getDescriptor();
} else {
return null;
}
}
/**
* Returns a list of Service Assemblies that contain SUs for the given component.
*
* @param componentName name of the component.
* @return list of Service Assembly names.
* @throws Exception if unable to retrieve service assembly list.
*/
public String[] getDeployedServiceAssembliesForComponent(String componentName) throws Exception {
try {
return registry.getDeployedServiceAssembliesForComponent(componentName);
} catch (Exception e) {
LOGGER.info("Error in getDeployedServiceAssembliesForComponent", e);
throw e;
}
}
/**
* Returns a list of components(to which SUs are targeted for) in a Service Assembly.
*
* @param saName name of the service assembly.
* @return list of component names.
* @throws Exception if unable to retrieve component list.
*/
public String[] getComponentsForDeployedServiceAssembly(String saName) throws Exception {
try {
return registry.getComponentsForDeployedServiceAssembly(saName);
} catch (Exception e) {
LOGGER.info("Error in getComponentsForDeployedServiceAssembly", e);
throw e;
}
}
/**
* Returns a boolean value indicating whether the SU is currently deployed.
*
* @param componentName - name of component.
* @param suName - name of the Service Unit.
* @return boolean value indicating whether the SU is currently deployed.
* @throws Exception if unable to return status of service unit.
*/
public boolean isDeployedServiceUnit(String componentName, String suName) throws Exception {
try {
return registry.isSADeployedServiceUnit(componentName, suName);
} catch (Exception e) {
LOGGER.info("Error in isSADeployedServiceUnit", e);
throw e;
}
}
/**
* Returns a boolean value indicating whether the SU can be deployed to a component.
*
* @param componentName - name of the component.
* @return boolean value indicating whether the SU can be deployed.
*/
public boolean canDeployToComponent(String componentName) {
ComponentMBeanImpl lcc = container.getComponent(componentName);
return lcc != null && lcc.isStarted() && lcc.getServiceUnitManager() != null;
}
/**
* Starts the service assembly and puts it in STARTED state.
*
* @param serviceAssemblyName - name of the service assembly.
* @return Result/Status of this operation.
* @throws Exception if operation fails.
*/
public String start(String serviceAssemblyName) throws Exception {
try {
if (serviceAssemblyName == null) {
throw ManagementSupport.failure("start",
"SA name must not be null");
}
ServiceAssemblyLifeCycle sa = registry.getServiceAssembly(
serviceAssemblyName);
if (sa == null) {
throw ManagementSupport.failure("start", "SA has not been deployed: "
+ serviceAssemblyName);
}
return sa.start(true);
} catch (Exception e) {
LOGGER.error("Error in start", e);
throw e;
}
}
/**
* Stops the service assembly and puts it in STOPPED state.
*
* @param serviceAssemblyName - name of the service assembly.
* @return Result/Status of this operation.
* @throws Exception if operation fails.
*/
public String stop(String serviceAssemblyName) throws Exception {
try {
if (serviceAssemblyName == null) {
throw ManagementSupport.failure("stop",
"SA name must not be null");
}
ServiceAssemblyLifeCycle sa = registry.getServiceAssembly(serviceAssemblyName);
if (sa == null) {
throw ManagementSupport.failure("stop", "SA has not been deployed: "
+ serviceAssemblyName);
}
return sa.stop(true, false);
} catch (Exception e) {
LOGGER.error("Error in stop", e);
throw e;
}
}
/**
* Shutdown the service assembly and puts it in SHUTDOWN state.
*
* @param serviceAssemblyName - name of the service assembly.
* @return Result/Status of this operation.
* @throws Exception if operation fails.
*/
public String shutDown(String serviceAssemblyName) throws Exception {
try {
if (serviceAssemblyName == null) {
throw ManagementSupport.failure("shutdown",
"SA name must not be null");
}
ServiceAssemblyLifeCycle sa = registry.getServiceAssembly(serviceAssemblyName);
if (sa == null) {
throw ManagementSupport.failure("shutdown", "SA has not been deployed: "
+ serviceAssemblyName);
}
return sa.shutDown(true);
} catch (Exception e) {
LOGGER.error("Error in shutDown", e);
throw e;
}
}
/**
* Returns the state of service assembly.
*
* @param serviceAssemblyName - name of the service assembly.
* @return State of the service assembly.
* @throws Exception if operation fails.
*/
public String getState(String serviceAssemblyName) throws Exception {
try {
ServiceAssemblyLifeCycle sa = registry.getServiceAssembly(serviceAssemblyName);
return sa.getCurrentState();
} catch (Exception e) {
LOGGER.info("Error in getState", e);
throw e;
}
}
/**
* See if an Sa is already deployed
*
* @param serviceAssemblyName - name of the service assembly.
* @return true if already deployed
*/
protected boolean isSaDeployed(String serviceAssemblyName) {
return registry.getServiceAssembly(serviceAssemblyName) != null;
}
/**
* Deploy an SA
*
* @param tmpDir
* @param sa
* @return result/status of the deployment in xml format
* @throws Exception in xml format
*/
protected String deployServiceAssembly(File tmpDir, ServiceAssembly sa) throws Exception {
String assemblyName = sa.getIdentification().getName();
ServiceAssemblyEnvironment env = environmentContext.getNewServiceAssemblyEnvironment(assemblyName);
File saDirectory = env.getInstallDir();
// move the assembly to a well-named holding area
LOGGER.debug("Moving {} to {}", tmpDir.getAbsolutePath(), saDirectory.getAbsolutePath());
saDirectory.getParentFile().mkdirs();
if (!tmpDir.renameTo(saDirectory)) {
throw ManagementSupport.failure("deploy", "Failed to rename " + tmpDir + " to " + saDirectory);
}
// Check all SUs requirements
ServiceUnit[] sus = sa.getServiceUnits();
if (sus != null) {
checkSus(saDirectory, sus);
}
// Everything seems ok, so deploy all SUs
int nbFailures = 0;
List<Element> componentResults = new ArrayList<Element>();
List<String> suKeys = new ArrayList<String>();
if (sus != null) {
for (int i = 0; i < sus.length; i++) {
File targetDir = null;
String suName = sus[i].getIdentification().getName();
String artifact = sus[i].getTarget().getArtifactsZip();
String componentName = sus[i].getTarget().getComponentName();
// TODO: skip duplicates
// Unpack SU
try {
File artifactFile = new File(saDirectory, artifact);
targetDir = env.getServiceUnitDirectory(componentName, suName);
LOGGER.debug("Unpack service unit archive {} to {}", artifactFile, targetDir);
FileUtil.unpackArchive(artifactFile, targetDir);
} catch (IOException e) {
nbFailures++;
componentResults.add(ManagementSupport.createComponentFailure(
"deploy", componentName,
"Error unpacking service unit", e));
continue;
}
// Deploy it
boolean success = false;
try {
ComponentMBeanImpl lcc = container.getComponent(componentName);
ServiceUnitManager sum = lcc.getServiceUnitManager();
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(lcc.getComponent().getClass().getClassLoader());
String resultMsg = sum.deploy(suName, targetDir.getAbsolutePath());
success = getComponentTaskResult(resultMsg, componentName, componentResults, true);
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
// TODO: need to register the SU somewhere to keep track of its state
} catch (Exception e) {
getComponentTaskError(e, componentName, componentResults);
}
if (success) {
suKeys.add(registry.registerServiceUnit(sus[i], assemblyName, targetDir));
} else {
nbFailures++;
}
}
}
// Note: the jbi spec says that if at least one deployment succeeds,
// this should be a SUCCESS. However, ServiceMix handles SA in an
// atomic way: for a given operation on an SA, all operations on SU
// should succeed. This is clearly a minor violation of the spec.
//
// Failure
if (nbFailures > 0) {
// Undeploy SUs
for (Iterator<String> iter = suKeys.iterator(); iter.hasNext();) {
try {
String suName = iter.next();
ServiceUnitLifeCycle su = registry.getServiceUnit(suName);
undeployServiceUnit(su);
} catch (Exception e) {
LOGGER.warn("Error undeploying SU", e);
}
}
// Delete SA deployment directory
FileUtil.deleteFile(saDirectory);
throw ManagementSupport.failure("deploy", componentResults);
// Success
} else {
// Register SA
String[] deployedSUs = suKeys.toArray(new String[suKeys.size()]);
ServiceAssemblyLifeCycle salc = registry.registerServiceAssembly(sa, deployedSUs, env);
salc.writeRunningState();
// Build result string
if (nbFailures > 0) {
return ManagementSupport.createWarningMessage("deploy", "Failed to deploy some service units", componentResults);
} else {
return ManagementSupport.createSuccessMessage("deploy", componentResults);
}
}
}
protected void checkSus(File saDirectory, ServiceUnit[] sus) throws Exception {
for (int i = 0; i < sus.length; i++) {
String suName = sus[i].getIdentification().getName();
String artifact = sus[i].getTarget().getArtifactsZip();
String componentName = sus[i].getTarget().getComponentName();
File artifactFile = new File(saDirectory, artifact);
if (!artifactFile.exists()) {
throw ManagementSupport.failure("deploy", "Artifact " + artifact + " not found for service unit " + suName);
}
ComponentMBeanImpl lcc = container.getComponent(componentName);
if (lcc == null) {
throw ManagementSupport.failure("deploy", "Target component " + componentName
+ " for service unit " + suName + " is not installed");
}
if (!lcc.isStarted()) {
throw ManagementSupport.failure("deploy", "Target component " + componentName
+ " for service unit " + suName + " is not started");
}
if (lcc.getServiceUnitManager() == null) {
throw ManagementSupport.failure("deploy", "Target component " + componentName
+ " for service unit " + suName + " does not accept deployments");
}
// TODO: check duplicates here ?
if (isDeployedServiceUnit(componentName, suName)) {
throw ManagementSupport.failure("deploy", "Service unit " + suName
+ " is already deployed on component " + componentName);
}
}
}
protected void getComponentTaskError(Exception exception, String component, List<Element> results) {
Element result = null;
try {
Document doc = parse(exception.getMessage());
result = getElement(doc, "component-task-result");
} catch (Exception e) {
result = ManagementSupport.createComponentFailure(
"deploy", component,
"Unable to parse result string", exception);
}
if (result != null) {
results.add(result);
}
}
protected boolean getComponentTaskResult(String resultMsg, String component, List<Element> results, boolean success) {
Element result = null;
try {
Document doc = parse(resultMsg);
result = getElement(doc, "component-task-result");
Element e = getChildElement(result, "component-task-result-details");
e = getChildElement(e, "task-result-details");
e = getChildElement(e, "task-result");
String r = DOMUtil.getElementText(e);
if (!"SUCCESS".equals(r)) {
success = false;
}
} catch (Exception e) {
// The component did not throw an exception upon deployment,
// but the result string is not compliant, so issue a warning
// and consider this is a successfull deployment
try {
if (success) {
result = ManagementSupport.createComponentWarning(
"deploy", component,
"Unable to parse result string", e);
} else {
result = ManagementSupport.createComponentFailure(
"deploy", component,
"Unable to parse result string", e);
}
} catch (Exception e2) {
LOGGER.error(e2.getMessage());
result = null;
}
}
if (result != null) {
results.add(result);
}
return success;
}
protected Document parse(String result) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringElementContentWhitespace(true);
factory.setIgnoringComments(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new InputSource(new StringReader(result)));
}
protected Element getElement(Document doc, String name) {
NodeList l = doc.getElementsByTagNameNS("http://java.sun.com/xml/ns/jbi/management-message", name);
return (Element) l.item(0);
}
protected Element getChildElement(Element element, String name) {
NodeList l = element.getElementsByTagNameNS("http://java.sun.com/xml/ns/jbi/management-message", name);
return (Element) l.item(0);
}
protected void undeployServiceUnit(ServiceUnitLifeCycle su) throws DeploymentException {
String name = su.getName();
String componentName = su.getComponentName();
File targetDir = su.getServiceUnitRootPath();
registry.unregisterServiceUnit(su.getKey());
// unpack the artifact
// now get the component and give it a SA
ComponentMBeanImpl component = container.getComponent(componentName);
if (component != null) {
ServiceUnitManager sum = component.getServiceUnitManager();
if (sum != null) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(component.getComponent().getClass().getClassLoader());
sum.undeploy(name, targetDir.getAbsolutePath());
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
FileUtil.deleteFile(targetDir);
}
} else {
FileUtil.deleteFile(targetDir);
}
LOGGER.info("UnDeployed ServiceUnit {} from Component: {}", name, componentName);
}
/**
* Find runnning state and things deployed before shutdown
*/
protected void buildState() {
LOGGER.info("Restoring service assemblies");
// walk through deployed SA's
File top = environmentContext.getServiceAssembliesDir();
if (top == null || !top.exists() || !top.isDirectory()) {
return;
}
File[] files = top.listFiles();
if (files == null) {
return;
}
// Initialize all assemblies
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
String assemblyName = files[i].getName();
try {
ServiceAssemblyEnvironment env = environmentContext.getServiceAssemblyEnvironment(assemblyName);
Descriptor root = DescriptorFactory.buildDescriptor(env.getInstallDir());
if (root != null) {
ServiceAssembly sa = root.getServiceAssembly();
if (sa != null && sa.getIdentification() != null) {
registry.registerServiceAssembly(sa, env);
}
}
} catch (Exception e) {
LOGGER.error("Failed to initialized service assembly: {}", assemblyName, e);
}
}
}
}
}