All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jp.go.nict.langrid.servicecontainer.handler.axis.SGAxisServlet Maven / Gradle / Ivy

The newest version!
/*
 * This is a program for Language Grid Core Node. This combines multiple language resources and provides composite language services.
 * Copyright (C) 2005-2011 NICT Language Grid Project.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see .
 */
package jp.go.nict.langrid.servicecontainer.handler.axis;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;

import jp.go.nict.langrid.commons.lang.StringUtil;
import jp.go.nict.langrid.commons.parameter.ParameterContext;
import jp.go.nict.langrid.commons.rpc.RpcHeader;
import jp.go.nict.langrid.commons.transformer.ClassToClassNameTransformer;
import jp.go.nict.langrid.commons.util.Pair;
import jp.go.nict.langrid.commons.ws.ServiceContext;
import jp.go.nict.langrid.commons.ws.ServletConfigServiceContext;
import jp.go.nict.langrid.commons.ws.ServletServiceContext;
import jp.go.nict.langrid.commons.ws.param.ServletConfigParameterContext;
import jp.go.nict.langrid.servicecontainer.handler.ServiceFactory;
import jp.go.nict.langrid.servicecontainer.handler.ServiceLoader;
import jp.go.nict.langrid.servicecontainer.handler.annotation.ServicesUtil;
import jp.go.nict.langrid.servicecontainer.handler.loader.ServiceFactoryLoader;

import org.apache.axis.AxisFault;
import org.apache.axis.EngineConfiguration;
import org.apache.axis.WSDDEngineConfiguration;
import org.apache.axis.deployment.wsdd.WSDDBeanMapping;
import org.apache.axis.deployment.wsdd.WSDDConstants;
import org.apache.axis.deployment.wsdd.WSDDDeployment;
import org.apache.axis.deployment.wsdd.WSDDService;
import org.apache.axis.transport.http.AxisServlet;

/**
 * 
 * 
 * @author Takao Nakaguchi
 */
public class SGAxisServlet extends AxisServlet {
	/**
	 * 
	 * 
	 */
	public static ServiceContext getCurrentServletServiceContext(){
		return currentServletConfig.get();
	}

	public static ServiceLoader getCurrentServletServiceLoader() {
		return currentServiceLoader.get();
	}

	@Override
	public void init() throws ServletException {
		super.init();
		ParameterContext pc = new ServletConfigParameterContext(getServletConfig(), true);
		String mappings = pc.getString("wsddBeanNamespaceMappings", "");
		initNamespaceMappings(mappings);
		this.defaultLoaders = ServicesUtil.getServiceFactoryLoaders(getClass());
		updateServiceDeployment();
	}

	protected ServiceFactoryLoader[] getDefaultServiceFactoryLoaders(){
		return defaultLoaders;
	}


	private synchronized void updateServiceDeployment() throws ServletException{
		lastUpdate = System.currentTimeMillis();
		try{
			EngineConfiguration config = getEngine(this).getConfig();
			if(!(config instanceof WSDDEngineConfiguration)) return;
			loadServicesFromServicesPath(
					((WSDDEngineConfiguration)config).getDeployment()
					, new ServiceLoader(new ServletConfigServiceContext(getServletConfig()), getDefaultServiceFactoryLoaders())
					);
		} catch(AxisFault e){
		} catch(IOException e){
			throw new ServletException(e);
		}
	}

	private void loadServicesFromServicesPath(WSDDDeployment deployment, ServiceLoader loader)
	throws IOException{
		for(String name: loader.listServiceNames()){
			if(deployment.getWSDDService(new QName(name)) != null) continue;

			ServiceFactory factory = null;
			try{
				factory = loader.loadServiceFactory(
						Thread.currentThread().getContextClassLoader()
						, name);
			} catch(RuntimeException e){
				if(e.getClass().getName().equals("BeanCreationException")){
					logger.log(
							Level.WARNING
							, "ignore service \"" + name + "\" because interface class not determined."
							, e);
					continue;
				}
				throw e;
			}
			Set> interfaceClasses = factory.getInterfaces();
			if(interfaceClasses.isEmpty()){
				logger.warning("ignore service \"" + name + "\" because interface class not determined.");
				continue;
			}

			WSDDService s = new WSDDService();
			s.setName(name);
			s.getServiceDesc().setName(name);
			s.setProviderQName(new QName(
					"http://xml.apache.org/axis/wsdd/providers/java"
					, "SGRPC"));
			s.setParameter("className", interfaceClasses.iterator().next().getName());
			s.setParameter("x_sg_interfaces"
					, StringUtil.join(interfaceClasses.toArray(new Class[]{}), new ClassToClassNameTransformer(), ",")
					);
			s.setParameter("x_sg_managed", "true");
			for(Class c : interfaceClasses){
				addBeanMapping(s, c.getName());
			}
			deployment.deployService(s);
		}
	}

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		ServiceContext sc = new ServletServiceContext(req, new ArrayList());
		currentServletConfig.set(sc);
		currentServiceLoader.set(new ServiceLoader(sc, getDefaultServiceFactoryLoaders()));
		try{
			if((60 * 1000) <= (System.currentTimeMillis() - lastUpdate)){
				updateServiceDeployment();
			} else{
				String serviceName = SGJavaProvider.getServiceName(sc);
				if(serviceName != null && getEngine(this).getService(serviceName) == null){
					updateServiceDeployment();
				}
			}
			super.service(req, resp);
		} finally{
			currentServiceLoader.remove();
			currentServletConfig.remove();
		}
	}

	private void initNamespaceMappings(String mappings){
		for(String m : mappings.split("\\n")){
			String[] values = m.trim().split(", *");
			if(values.length < 2 || values[0].length() == 0) continue;
			namespaceMappings.add(Pair.create(values[0], values[1]));
		}
	}

	private void addBeanMapping(WSDDService service, String interfaceClass){
		try {
			Set> visited = new HashSet>();
			Deque> classes = new LinkedList>();
			Class clazz = Class.forName(interfaceClass);
			Set> mappedClasses = new HashSet>();
			classes.addLast(clazz);
			visited.add(clazz);
			while(clazz != null && !clazz.equals(Object.class)){
				for(Method m : clazz.getDeclaredMethods()){
					addBeanMapping(service, m.getReturnType(), mappedClasses);
					for(Class a : m.getParameterTypes()){
						addBeanMapping(service, a, mappedClasses);
					}
					for(Class e : m.getExceptionTypes()){
						addBeanMapping(service, e, mappedClasses);
					}
				}
				if(clazz.isInterface()){
					for(Class clz : clazz.getInterfaces()){
						if(!visited.contains(clz)){
							classes.add(clz);
							visited.add(clz);
						}
					}
				} else{
					Class clz = clazz.getSuperclass();
					if(!visited.contains(clz)){
						classes.add(clz);
						visited.add(clz);
					}
				}
				clazz = classes.pollFirst();
			}
		} catch (ClassNotFoundException e) {
		}
	}

	private void addBeanMapping(WSDDService service, Class clazz, Collection> mappedClasses){
		while(clazz != null){
			while(clazz.isArray()){
				clazz = clazz.getComponentType();
			}
			if(!needsMapping(clazz)) return;
			if(mappedClasses.contains(clazz)) return;
			mappedClasses.add(clazz);

			for(Method m : clazz.getDeclaredMethods()){
				if(!m.isSynthetic()
						&& m.getName().startsWith("get")
						&& m.getParameterTypes().length == 0
						&& (m.getModifiers() & Modifier.PUBLIC) != 0){
					addBeanMapping(service, m.getReturnType(), mappedClasses);
				}
			}

			WSDDBeanMapping m = new WSDDBeanMapping();
			m.setLanguageSpecificType(clazz);
			Package p = clazz.getPackage();
			if(p == null){
				// arrayちゃんと処理できてる?
				// System.out.println(clazz);
			}
			String packageName = p != null ? p.getName() : "";
			String simpleName = clazz.getSimpleName();
			boolean qnameSet = false;
			for(Pair n : namespaceMappings){
				if(packageName.startsWith(n.getFirst())){
					String rest = packageName.substring(n.getFirst().length()).replace('.', '/');
					String nsPrefix = n.getSecond();
					if(rest.length() > 0){
						rest = rest + "/";
						if(nsPrefix.endsWith("/") && rest.charAt(0) == '/'){
							rest = rest.substring(1);
						}
					}
					m.setQName(new QName(n.getSecond() + rest, simpleName));
					qnameSet = true;
					break;
				}
			}
			if(!qnameSet){
				m.setQName(new QName("uri:" + packageName + "/"	, simpleName));
			}
	        m.setSerializer(WSDDConstants.BEAN_SERIALIZER_FACTORY);
	        m.setDeserializer(WSDDConstants.BEAN_DESERIALIZER_FACTORY);
			service.addTypeMapping(m);

			clazz = clazz.getSuperclass();
		}
	}

	private boolean needsMapping(Class clazz){
		if(clazz.isPrimitive()) return false;
		if(clazz.equals(Object.class)) return false;
		if(clazz.equals(Class.class)) return false;
		return !ignoreClasses.contains(clazz);
	}

	private List> namespaceMappings = new ArrayList>();
	private long lastUpdate;
	private ServiceFactoryLoader[] defaultLoaders;
	private static final long serialVersionUID = 4086806608108580827L;
	private static Set> ignoreClasses = new HashSet>();
	private static ThreadLocal currentServletConfig = new ThreadLocal();
	private static ThreadLocal currentServiceLoader = new ThreadLocal();
	private static Logger logger = Logger.getLogger(SGAxisServlet.class.getName());

	static{
		ignoreClasses.add(Object.class);
		ignoreClasses.add(Exception.class);
		ignoreClasses.add(String.class);
		ignoreClasses.add(Void.class);
		ignoreClasses.add(Byte.class);
		ignoreClasses.add(Character.class);
		ignoreClasses.add(Short.class);
		ignoreClasses.add(Integer.class);
		ignoreClasses.add(Long.class);
		ignoreClasses.add(Float.class);
		ignoreClasses.add(Double.class);
		ignoreClasses.add(Calendar.class);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy