/*
* Copyright (c) 2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.wso2.carbon.sts;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.deployment.DeploymentConstants;
import org.apache.axis2.deployment.DeploymentEngine;
import org.apache.axis2.deployment.DescriptionBuilder;
import org.apache.axis2.deployment.ServiceBuilder;
import org.apache.axis2.deployment.ServiceGroupBuilder;
import org.apache.axis2.deployment.repository.util.ArchiveReader;
import org.apache.axis2.deployment.repository.util.DeploymentFileData;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.AxisServiceGroup;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.Bundle;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.sts.internal.STSServiceDataHolder;
import org.wso2.carbon.utils.AbstractAxis2ConfigurationContextObserver;
import org.wso2.carbon.utils.IOStreamUtils;
import org.wso2.carbon.utils.deployment.Axis2ServiceRegistry;
import org.wso2.carbon.utils.deployment.BundleClassLoader;
import javax.xml.stream.XMLStreamException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
/**
* This deploys a wso2carbon-sts service when tenant is loaded.
*/
public class STSDeploymentListener extends AbstractAxis2ConfigurationContextObserver {
private static final Log log = LogFactory.getLog(STSDeploymentListener.class);
private static String componentsDirPath;
static {
String carbonRepo = System.getenv("CARBON_REPOSITORY");
if (carbonRepo == null) {
carbonRepo = System.getProperty("carbon.repository");
}
if (carbonRepo == null) {
carbonRepo = System.getProperty("carbon.home") + File.separator + "repository";
}
componentsDirPath = carbonRepo + File.separator + "components";
}
@Override
public void createdConfigurationContext(ConfigurationContext configContext) {
AxisService service = null;
try {
service = configContext.getAxisConfiguration().getService("wso2carbon-sts");
} catch (AxisFault axisFault) {
// just ignore service is not in axis2 configuration
if (log.isDebugEnabled()) {
log.debug("wso2carbon-sts service is not available", axisFault);
}
}
// creating service if it is null
if (service == null) {
configContext.getAxisConfiguration().addObservers(new STSDeploymentInterceptor());
Bundle bundle = STSServiceDataHolder.getInstance().getBundle();
AxisServiceGroup serviceGroup = createService(bundle, configContext);
if (serviceGroup != null) {
try {
configContext.getAxisConfiguration().addServiceGroup(serviceGroup);
} catch (AxisFault axisFault) {
log.error("Error occurs while adding wso2carbon-sts service group in to axis2" +
"configuration of tenant " +
CarbonContext.getThreadLocalCarbonContext().getTenantId(), axisFault);
}
}
}
}
private AxisServiceGroup createService(Bundle bundle, ConfigurationContext configContext) {
Enumeration enumeration = bundle.findEntries("META-INF", "*services.xml", true);
AxisServiceGroup serviceGroup = null;
AxisConfiguration axisConfiguration = configContext.getAxisConfiguration();
if (enumeration != null && enumeration.hasMoreElements()) {
try {
serviceGroup = new AxisServiceGroup(axisConfiguration);
ClassLoader loader = new BundleClassLoader(bundle, Axis2ServiceRegistry.class.getClassLoader());
URL url = (URL) enumeration.nextElement();
Dictionary headers = bundle.getHeaders();
String bundleSymbolicName = (String) headers.get("Bundle-SymbolicName");
serviceGroup.setServiceGroupName(bundleSymbolicName);
serviceGroup.setServiceGroupClassLoader(loader);
InputStream inputStream = url.openStream();
DescriptionBuilder builder = new DescriptionBuilder(inputStream, configContext);
OMElement rootElement = builder.buildOM();
String elementName = rootElement.getLocalName();
HashMap<String, AxisService> wsdlServicesMap = processWSDL(bundle);
if (MapUtils.isNotEmpty(wsdlServicesMap)) {
for (AxisService service : wsdlServicesMap.values()) {
Iterator<AxisOperation> operations = service.getOperations();
while (operations.hasNext()) {
AxisOperation axisOperation = operations.next();
axisConfiguration.getPhasesInfo().setOperationPhases(axisOperation);
}
}
}
if (DeploymentConstants.TAG_SERVICE.equals(elementName)) {
AxisService axisService = new AxisService(bundleSymbolicName);
axisService.setParent(serviceGroup);
axisService.setClassLoader(loader);
ServiceBuilder serviceBuilder = new ServiceBuilder(configContext, axisService);
serviceBuilder.setWsdlServiceMap(wsdlServicesMap);
AxisService service = serviceBuilder.populateService(rootElement);
ArrayList<AxisService> serviceList = new ArrayList<AxisService>();
serviceList.add(service);
DeploymentEngine.addServiceGroup(serviceGroup,
serviceList,
null,
null,
axisConfiguration);
if (log.isDebugEnabled()) {
log.debug("Deployed wso2carbon-sts service");
}
} else if (DeploymentConstants.TAG_SERVICE_GROUP.equals(elementName)) {
ServiceGroupBuilder groupBuilder =
new ServiceGroupBuilder(rootElement, wsdlServicesMap, configContext);
ArrayList<? extends AxisService> serviceList = groupBuilder.populateServiceGroup(serviceGroup);
DeploymentEngine.addServiceGroup(serviceGroup,
serviceList,
null,
null,
axisConfiguration);
if (log.isDebugEnabled()) {
log.debug("Deployed wso2carbon-sts service group ");
}
}
} catch (AxisFault axisFault) {
log.error("Error occur while deploying wso2carbon-sts service for tenant " +
CarbonContext.getThreadLocalCarbonContext().getTenantId(), axisFault);
} catch (XMLStreamException e) {
log.error("Error occur while deploying wso2carbon-sts service for tenant " +
CarbonContext.getThreadLocalCarbonContext().getTenantId(), e);
} catch (IOException e) {
log.error("Error occur while deploying wso2carbon-sts service for tenant " +
CarbonContext.getThreadLocalCarbonContext().getTenantId(), e);
}
}
return serviceGroup;
}
private HashMap processWSDL(Bundle bundle) throws IOException, XMLStreamException {
Enumeration enumeration = bundle.findEntries("META-INF", "*.wsdl", true);
if (enumeration == null) {
return new HashMap();
}
String bundleLocation = bundle.getLocation();
// Sometimes value of the bundleLocation can be a string such as the following.
// reference:file:plugins/org.wso2.carbon.statistics-3.2.0.jar
// In these situations we need to remove the "reference:" part from the bundleLocation.
if (bundleLocation.startsWith("reference:")) {
bundleLocation = bundleLocation.substring("reference:".length());
}
// Extracting bundle file name.
String[] subStrings = bundleLocation.split("/");
String bundleFileName = subStrings[subStrings.length - 1];
File bundleFile;
URL bundleURL = new URL(bundleLocation);
if ("file".equals(bundleURL.getProtocol())) {
bundleFile = new File(bundleURL.getFile());
} else {
InputStream bundleStream = bundleURL.openStream();
// Generate temp file path for the bundle.
String tempBundleDirPath = System.getProperty("java.io.tmpdir") + File.separator + "bundles";
//Creating a temp dir to store bundles.
File tempBundleDir = new File(tempBundleDirPath);
if (!tempBundleDir.exists() && !tempBundleDir.mkdir()) {
log.warn("Could not create temp bundle directory " + tempBundleDir.getAbsolutePath());
return new HashMap();
}
bundleFile = new File(tempBundleDirPath, bundleFileName);
OutputStream bundleFileOutputSteam = new FileOutputStream(bundleFile);
// Copying input stream to the file output stream
IOStreamUtils.copyInputStream(bundleStream, bundleFileOutputSteam);
}
if (!bundleFile.exists()) {
//If the bundle does not exits, then we check in the plugins dir.
bundleFile = new File(componentsDirPath + File.separator + bundleURL.getFile());
}
if (!bundleFile.exists()) {
return new HashMap();
}
DeploymentFileData deploymentFileData = new DeploymentFileData(bundleFile);
ArchiveReader archiveReader = new ArchiveReader();
return archiveReader.processWSDLs(deploymentFileData);
}
}