/*
* 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.muse.core.platform.osgi.axis2;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.UnknownHostException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.muse.core.AbstractEnvironment;
import org.apache.muse.core.platform.axis2.AxisEnvironment;
import org.apache.muse.core.platform.osgi.OSGiEnvironment;
import org.apache.muse.core.platform.osgi.util.BundleRootHelper;
import org.apache.muse.core.platform.osgi.util.OSGiReflectUtilHelper;
import org.apache.muse.util.messages.Messages;
import org.apache.muse.util.messages.MessagesFactory;
import org.apache.muse.ws.addressing.EndpointReference;
import org.apache.muse.ws.addressing.MessageHeaders;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.apache.muse.core.platform.osgi.OSGiPlatformConstants;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.OperationContext;
/**
*
* Axis2Environment is an OSGi aware extension of the Muse AxisEnvironment. This class
* implements the <code>OSGiEnvironment</code> interface, which allows the Muse environment
* to access the Bundle context of an executing thread.
*
* @see OSGiEnvironment
*
* @author Joel Hawkins (joelh)
*
*/
public class Axis2Environment extends AxisEnvironment implements
OSGiEnvironment {
//
// Used to lookup all exception messages
//
private static Messages _MESSAGES = MessagesFactory.get(Axis2Environment.class);
//
// The name of the property that has the J2EE HttpServletRequest
//
private static final String _REQUEST_PROPERTY = "transport.http.servletRequest";
//
// The name of the property that has the J2EE ServletEndpointContext
//
private static final String _SEC_PROPERTY = "servletEndpointContext";
//
// The WAR installation directory
//
private File _realDirectory = null;
private boolean backLevelServletAPI = false;
private static BundleContext bundleContext;
private InheritableThreadLocal localEnvironmentContext = new InheritableThreadLocal();
/**
* setter for the the bundle context of the hosting bundle.
*/
public static void setBundleContext(BundleContext context) {
bundleContext = context;
}
/**
* getter for the Bundle corresponding to the executing thread
* @return the current thread's Bundle
*/
public Bundle getThreadLocalBundle() {
return (Bundle) localEnvironmentContext.get();
}
/**
* setter for the Bundle corresponding to the executing thread
* @param bundle the current thread's Bundle
*/
public void setThreadLocalBundle(Bundle bundle) {
localEnvironmentContext.set(bundle);
OSGiReflectUtilHelper.getDefault().setThreadLocalBundle(bundle);
}
public Axis2Environment() {
MessageHeaders wsa = convertContext();
addAddressingContext(wsa);
String address = wsa.getToAddress().getAddress().toString();
setDefaultURI(getDeploymentURI(address));
//TODO enable real back-level servlet check
//int major = servletContext.getMajorVersion();
//int minor = servletContext.getMinorVersion();
//if (major <= 2 && minor <= 1)
backLevelServletAPI = true;
MessageContext message = MessageContext.getCurrentMessageContext();
_realDirectory = message.getConfigurationContext().getRealPath("/");
//_realDirectory = new File(address);
}
public EndpointReference getDeploymentEPR() {
return super.getDeploymentEPR();
}
public String getDefaultURI()
{
String defaultURI = super.getDefaultURI();
OSGiReflectUtilHelper helper = OSGiReflectUtilHelper.getDefault();
Bundle bundle = helper.getThreadLocalBundle();
String context = BundleRootHelper.getContextForBundle(bundle);
if(context != null && defaultURI != null){
int first = defaultURI.indexOf("/",8);
defaultURI = defaultURI.substring(0,first+1);
defaultURI = defaultURI + context + "/services/blah";
}
return defaultURI;
}
/**
*
* @param request
*
* @return The URI being targeted by the current request. This URI includes
* an IP address rather than a host name, because we often use it to
* create EPRs/URIs for remote users based on the results of a local
* request. Just because the initial request was local doesn't mean
* we should represent ourselves to remote users with a local name.
* It also means that remote systems don't have to have a hosts
* lookup that includes our endpoint's machine.
*
*/
protected URI getDeploymentURI(HttpServletRequest request) {
String urlWithHostName = null;
String ip = null;
String eprContext = null;
Bundle bundle = getThreadLocalBundle();
if(bundle != null){
eprContext = (String)bundle.getHeaders().get(OSGiPlatformConstants.MANAGEMENT_CONTEXT_HEADER);
}
String portString = "";
int serverPort = request.getServerPort();
if(serverPort != 80){
portString = ":" + Integer.toString(serverPort, 10);
}
if (!this.backLevelServletAPI) {
urlWithHostName = request.getRequestURL().toString();
} else {
urlWithHostName = request.getRequestURI().toString();
String pathInfo = request.getPathInfo();
String reqURI = request.getRequestURI();
urlWithHostName = "http://blah" +portString+ urlWithHostName;
}
try {
ip = InetAddress.getLocalHost().getHostAddress();
if(portString.length() > 0) ip = ip.concat(portString);
}
catch (UnknownHostException error) {
throw new RuntimeException(error);
}
int start = urlWithHostName.indexOf("://") + 3;
int end = urlWithHostName.indexOf('/', start);
int port = urlWithHostName.indexOf(':', start);
//
// check for port - we don't want to lose that in the replacement
//
if (port >= 0 && port < end)
end = port;
StringBuffer urlWithIP = new StringBuffer(urlWithHostName.length());
urlWithIP.append(urlWithHostName.substring(0, start));
urlWithIP.append(ip);
if(eprContext == null) urlWithIP.append(urlWithHostName.substring(end));
else{
urlWithIP.append("/"+eprContext);
int servicesStart = urlWithHostName.indexOf("/services/");
urlWithIP.append(urlWithHostName.substring(servicesStart));
}
return URI.create(urlWithIP.toString());
}
/**
* @return A <File> object corresponding to the executing thread's Bundle's
* root directory. This method uses the <code>BundleRootHelper</code> class
* to resolve the root directory.
*
* @see BundleRootHelper
*/
public File getRealDirectory() {
Bundle bundle = getThreadLocalBundle();
if(bundle != null) {
File root = BundleRootHelper.getRootForBundle(bundle);
if(root != null) return root;
}
return _realDirectory;
}
/**
*
*/
public URL getDataResource(String path) {
if (path == null)
throw new NullPointerException(_MESSAGES.get("NullResourcePath"));
File file = new File(_realDirectory, path);
try {
return file.toURL();
}
catch (MalformedURLException error) {
throw new RuntimeException(error);
}
}
/**
* this method returns an InputStream for a resource based on the
* executing thread's Bundle context.
* @param path the path to the resource
* @return an <code>InputStream</code> corresponding to the resource if the resource is found,
* otherwise <code>null</code>
*/
public InputStream getDataResourceStream(String path) {
if (path == null)
throw new NullPointerException("NullResourcePath");
InputStream input = null;
Bundle bundle = getThreadLocalBundle();
if (bundle != null) {
URL url = bundle.getResource(path);
if (url != null) {
try {
input = url.openStream();
} catch (IOException ioe) {
input = null;
}
}
}
if (input == null)
input = this.getClass().getResourceAsStream(path);
if (input == null)
input = this.getClass().getResourceAsStream("/OSGI-INF/" + path);
if (input == null){
input = OSGiReflectUtilHelper.getDefault().getResource(path);
}
if(input == null && bundle != null){
try {
File file = BundleRootHelper.getRootForBundle(bundle);
File lastTry = new File(file.getAbsolutePath() +"/"+ path);
input = new FileInputStream(lastTry);
} catch(Throwable t){
throw new RuntimeException(t.getMessage(), t);
}
}
return input;
}
protected File createRealDirectoryFromContext(){
return null;
}
protected File createRealDirectory(){
//There is no real use for this, but we can't return a 'null', as the rest of
//Muse's initialization will fail
return bundleContext.getDataFile("");
}
}