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

org.mobicents.servlet.sip.startup.SipContextConfig Maven / Gradle / Ivy

There is a newer version: 4.0.128
Show newest version
/*
 * TeleStax, Open Source Cloud Communications  Copyright 2012. 
 * and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This 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 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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 software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.mobicents.servlet.sip.startup;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.servlet.ServletContext;

import org.apache.catalina.Context;
import org.apache.catalina.Host;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.core.StandardWrapper;
import org.apache.catalina.startup.Constants;
import org.apache.catalina.startup.ContextConfig;
import org.apache.catalina.startup.ExpandWar;
import org.apache.catalina.util.ContextName;
import org.apache.log4j.Logger;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.bcel.classfile.AnnotationEntry;
import org.apache.tomcat.util.bcel.classfile.ClassFormatException;
import org.apache.tomcat.util.bcel.classfile.ClassParser;
import org.apache.tomcat.util.bcel.classfile.JavaClass;
import org.apache.tomcat.util.descriptor.DigesterFactory;
import org.apache.tomcat.util.digester.Digester;
import org.mobicents.servlet.sip.annotations.AnnotationVerificationException;
import org.mobicents.servlet.sip.annotations.ClassFileScanner;
import org.mobicents.servlet.sip.catalina.CatalinaSipContext;
import org.mobicents.servlet.sip.catalina.SipDeploymentException;
import org.mobicents.servlet.sip.catalina.SipEntityResolver;
import org.mobicents.servlet.sip.catalina.SipRuleSet;
import org.mobicents.servlet.sip.core.SipContext;
import org.xml.sax.EntityResolver;

/**
 * Startup event listener for a the SipStandardContext that configures
 * the properties of that Context, and the associated defined servlets.
 * it extends the regular tomcat context config to be able to load sip
 * servlet applications.
 * 
 * @author Jean Deruelle
 * 
 */
public class SipContextConfig extends ContextConfig {	

	private static transient final Logger logger = Logger.getLogger(SipContextConfig.class);
	//Issue 77: http://code.google.com/p/sipservlets/issues/detail?id=77
	//commenting out to avoid double parsing of annotations if there is some
//	private Boolean hasWebAnnotations = false;


	/**
	 * {@inheritDoc}
	 */
	public void lifecycleEvent(LifecycleEvent event) {
		try {
			super.lifecycleEvent(event);
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	@Override
	protected synchronized void configureStart() {	
		super.configureStart();
		if(context instanceof SipContext) {
			if(logger.isDebugEnabled()) {
				logger.debug("starting sipContextConfig");
			}
			ServletContext servletContext = context.getServletContext();
			
			// commenting out to avoid double parsing of annotations if there is some and calling 
			// super.configureStart at the beginning of the method to make sure we always parse annotations
			
			// calling start on the parent to initialize web resources of the web
			// app if any. That mean that this is a converged application.
//			InputStream webXmlInputStream = servletContext
//				.getResourceAsStream(Constants.ApplicationWebXml);
//			context.setWrapperClass(StandardWrapper.class.getName());						
//			if (webXmlInputStream != null) {
//				if(logger.isDebugEnabled()) {
//					logger.debug(Constants.ApplicationWebXml + " has been found, calling super.start() !");
//				}
//				super.configureStart();
//			} else {
//				//Java Servlets 3.0 makes web.xml optional if the servlet is using annotations.
//				//So here we check for web servlet annotations.
//				checkWebAnnotations();
//			}
//
//			if(hasWebAnnotations){
//				super.configureStart();
//			}

			context.setWrapperClass(org.mobicents.servlet.sip.catalina.SipServletImpl.class.getName());

			//annotations scanning
			Host host = (Host) context.getParent();
	        File appBase = host.getAppBaseFile();
	        
			ClassFileScanner scanner = new ClassFileScanner(appBase.getPath() +  File.separatorChar + ((CatalinaSipContext)context).getDocBase(), (CatalinaSipContext)context);
			try {
				scanner.scan();
			} catch (AnnotationVerificationException ave) {
				logger.error("An annotation didn't follow its annotation contract",
						ave);
				ok = false;
			}					

			String applicationSipXmlPath =  "/" + SipContext.APPLICATION_SIP_XML;
			InputStream sipXmlInputStream = servletContext
					.getResourceAsStream(applicationSipXmlPath);
			// compliance is now enforced in Tomcat 8
//			if(sipXmlInputStream == null) {
//				// http://code.google.com/p/sipservlets/issues/detail?id=167 Deal with strict compliance
//				if(logger.isInfoEnabled()) {
//					logger.info(applicationSipXmlPath + " has not been found, checking with a leading slash as servlet compliance might be enabled");
//				}
//				applicationSipXmlPath = "/" + SipContext.APPLICATION_SIP_XML;
//				sipXmlInputStream = servletContext
//						.getResourceAsStream(applicationSipXmlPath);
//				
//			}
			// processing of the sip.xml file
			if (sipXmlInputStream != null) {
				if(logger.isDebugEnabled()) {
					logger.debug(applicationSipXmlPath + " has been found !");
				}								

				Digester sipDigester =  DigesterFactory.newDigester(context.getXmlValidation(),
						context.getXmlNamespaceAware(),
						new SipRuleSet(),
						false);
				EntityResolver entityResolver = new SipEntityResolver();
				sipDigester.setValidating(false);		
				sipDigester.setEntityResolver(entityResolver);				
				//push the context to the digester
				sipDigester.push(context);
				sipDigester.setClassLoader(context.getClass().getClassLoader());
				//parse the sip.xml and populate the context with it
				try {
					sipDigester.resolveEntity(null, null);
					sipDigester.parse(sipXmlInputStream);
				} catch (Throwable e) {
					logger.warn("Impossible to parse the sip.xml deployment descriptor");
					ok = false;
				}
			} else {
				if(logger.isInfoEnabled()) {
					logger.info(applicationSipXmlPath + " has not been found !");
				}
				ok = false;
			}	

			// Use description from the annotations no matter if sip.xml parsing failed.
			if(scanner.isApplicationParsed()) { 
				ok = true;
			}

			checkSipDeploymentRequirements(context);

			if(!scanner.isApplicationParsed() && sipXmlInputStream != null) {
				context.setWrapperClass(StandardWrapper.class.getName());
			}

			// Make our application available if no problems were encountered
			if (ok) {
				if(logger.isDebugEnabled()) {
					logger.debug("sipContextConfig started");
				}
				context.setConfigured(true);						
			} else {
				logger.warn("sipContextConfig didn't start properly");
				context.setConfigured(false);
			}			
		} 
//		else {
//			super.configureStart();
//		}				
	}

	private void checkSipDeploymentRequirements(Context context) {
		if(((SipContext) context).getApplicationName() == null) {
			ok = false;
			context.setConfigured(false);				
			throw new SipDeploymentException("No app-name present in the sip.xml deployment descriptor or no SipApplication annotation defined");
		}

		boolean servletSelectionSet = false;
		String mainServlet = ((SipContext) context).getMainServlet();
		if(mainServlet != null && mainServlet.length() > 0) {
			servletSelectionSet = true;
		} else if(((SipContext) context).findSipServletMappings() != null && ((SipContext) context).findSipServletMappings().size() > 0) {
			servletSelectionSet = true;
		} else if(((SipContext) context).getSipRubyController() != null) {
			servletSelectionSet = true;
		}

		if(((SipContext) context).getChildrenMap().keySet().size() > 1 && !servletSelectionSet) {
			ok = false;
			context.setConfigured(false);
			throw new SipDeploymentException("the main servlet is not set and there is more than one servlet defined in the sip.xml or as annotations !");
		}
	}


	@Override
	protected synchronized void configureStop() {
		if(logger.isDebugEnabled()) {
			logger.debug("stopping sipContextConfig");
		}
		super.configureStop();
		if(logger.isDebugEnabled()) {
			logger.debug("sipContextConfig stopped");
		}
	}

	/**
     * Adjust docBase.
     */
    protected void fixDocBase()
        throws IOException {

        Host host = (Host) context.getParent();
        File appBase = host.getAppBaseFile();

        String docBase = context.getDocBase();
        if (docBase == null) {
            // Trying to guess the docBase according to the path
            String path = context.getPath();
            if (path == null) {
                return;
            }
            ContextName cn = new ContextName(path, context.getWebappVersion());
            docBase = cn.getBaseName();
        }

        File file = new File(docBase);
        if (!file.isAbsolute()) {
            docBase = (new File(appBase, docBase)).getPath();
        } else {
            docBase = file.getCanonicalPath();
        }
        file = new File(docBase);
        String origDocBase = docBase;

        ContextName cn = new ContextName(context.getPath(),
                context.getWebappVersion());
        String pathName = cn.getBaseName();

        boolean unpackWARs = true;
        if (host instanceof StandardHost) {
            unpackWARs = ((StandardHost) host).isUnpackWARs();
            if (unpackWARs && context instanceof StandardContext) {
                unpackWARs =  ((StandardContext) context).getUnpackWAR();
            }
        }

        if ((docBase.toLowerCase(Locale.ENGLISH).endsWith(".sar") || docBase.toLowerCase(Locale.ENGLISH).endsWith(".war")) && !file.isDirectory()) {
            if (unpackWARs) {
                URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/");
                docBase = ExpandWar.expand(host, war, pathName);
                file = new File(docBase);
                docBase = file.getCanonicalPath();
                if (context instanceof StandardContext) {
                    ((StandardContext) context).setOriginalDocBase(origDocBase);
                }
            } else {
                URL war =
                        new URL("jar:" + (new File (docBase)).toURI().toURL() + "!/");
                ExpandWar.validate(host, war, pathName);
            }
        } else {
            File docDir = new File(docBase);
            if (!docDir.exists()) {
            	String[] extensions = new String[] { ".sar", ".war" };
				for (String extension : extensions) {
					File archiveFile = new File(docBase + extension);
					if (archiveFile.exists()) {
						URL war =
		                        new URL("jar:" + archiveFile.toURI().toURL() + "!/");
						if (unpackWARs) {
							docBase = ExpandWar.expand(host, war, context
									.getPath());
							file = new File(docBase);
							docBase = file.getCanonicalPath();
						} else {
							docBase = archiveFile.getCanonicalPath();
							ExpandWar.validate(host, war, pathName);
						}

						break;
					}
				}
                if (context instanceof StandardContext) {
                    ((StandardContext) context).setOriginalDocBase(origDocBase);
                }
            }
        }

        if (docBase.startsWith(appBase.getPath() + File.separatorChar)) {
            docBase = docBase.substring(appBase.getPath().length());
            docBase = docBase.replace(File.separatorChar, '/');
            if (docBase.startsWith("/")) {
                docBase = docBase.substring(1);
            }
        } else {
            docBase = docBase.replace(File.separatorChar, '/');
        }

        context.setDocBase(docBase);

    }
//	
//	/**
//	 * Adjust docBase.
//	 */
//	protected void fixDocBase() throws IOException {
//		if(context instanceof SipContext) {
//			Host host = (Host) context.getParent();
//			String appBase = host.getAppBase();
//			boolean unpackWARs = true;
//			if (host instanceof StandardHost) {
//				unpackWARs = ((StandardHost) host).isUnpackWARs()
//				&& ((StandardContext) context).getUnpackWAR();
//			}
//			File canonicalAppBase = new File(appBase);
//			if (canonicalAppBase.isAbsolute()) {
//				canonicalAppBase = canonicalAppBase.getCanonicalFile();
//			} else {
//				canonicalAppBase = new File(System.getProperty("catalina.base"),
//						appBase).getCanonicalFile();
//			}
//			String docBase = context.getDocBase();
//			if (docBase == null) {
//				// Trying to guess the docBase according to the path
//				String path = context.getPath();
//				if (path == null) {
//					return;
//				}
//
//				ContextName cn = new ContextName(path, context.getWebappVersion());
//				docBase = cn.getBaseName();
//
//				//				if (path.equals("")) {
//				//					docBase = "ROOT";
//				//				} else {
//				//					if (path.startsWith("/")) {
//				//	                    docBase = path.substring(1).replace('/', '#');
//				//	                } else {
//				//	                    docBase = path.replace('/', '#');
//				//	                }
//				//				}
//			}
//			File file = new File(docBase);
//			if (!file.isAbsolute()) {
//				docBase = (new File(canonicalAppBase, docBase)).getPath();
//			} else {
//				docBase = file.getCanonicalPath();
//			}
//			file = new File(docBase);
//			//			String origDocBase = docBase;
//			if ((docBase.toLowerCase().endsWith(".sar") || docBase.toLowerCase()
//					.endsWith(".war"))
//					&& !file.isDirectory() && unpackWARs) {
//				URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/");
//		        //Issue:175: http://code.google.com/p/sipservlets/issues/detail?id=175
//				ContextName cn = new ContextName(context.getPath(),
//		                context.getWebappVersion());
//		        String contextPath = cn.getBaseName();
//
//				//				if (contextPath.equals("")) {
//				//					contextPath = "ROOT";
//				//				} else {
//				//		            if (contextPath.lastIndexOf('/') > 0) {
//				//		                contextPath = "/" + contextPath.substring(1).replace('/','#');
//				//		            }
//				//		        }
//
//				docBase = ExpandWar.expand(host, war, contextPath);
//				file = new File(docBase);
//				docBase = file.getCanonicalPath();
//				if (context instanceof CatalinaSipContext) {
//					FileDirContext fileDirContext =new FileDirContext();
//					fileDirContext.setDocBase(docBase);
//					((CatalinaSipContext) context).setResources(fileDirContext );
//				}
//			} else {
//				File docDir = new File(docBase);
//				if (!docDir.exists()) {
//					String[] extensions = new String[] { ".sar", ".war" };
//					for (String extension : extensions) {
//						File archiveFile = new File(docBase + extension);
//						if (archiveFile.exists()) {
//							if (unpackWARs) {
//								URL war = new URL("jar:" + archiveFile.toURI().toURL()
//										+ "!/");
//								docBase = ExpandWar.expand(host, war, context
//										.getPath());
//								file = new File(docBase);
//								docBase = file.getCanonicalPath();
//							} else {
//								docBase = archiveFile.getCanonicalPath();
//							}
//
//							break;
//						}
//					}
//					if (context instanceof CatalinaSipContext) {
//						FileDirContext fileDirContext =new FileDirContext();
//						fileDirContext.setDocBase(docBase);
//						((CatalinaSipContext) context).setResources(fileDirContext );
//					}
//				}
//			}
//			if (docBase.startsWith(canonicalAppBase.getPath() + File.separatorChar)) {
//				docBase = docBase.substring(canonicalAppBase.getPath().length());
//				docBase = docBase.replace(File.separatorChar, '/');
//				if (docBase.startsWith("/")) {
//					docBase = docBase.substring(1);
//				}
//			} else {
//				docBase = docBase.replace(File.separatorChar, '/');
//			}
//			context.setDocBase(docBase);
//		} else {
//			super.fixDocBase();
//		}
//	}

    // commenting out to avoid the parent calls out to those overidden methods and don't parse the annotations
	
	// Check for web servlet annotation in the /WEB-INF/classes	
//    protected void checkWebAnnotations(){
//		URL webinfClasses = null;
//		try{
//			webinfClasses = context.getServletContext().getResource("/WEB-INF/classes");
//		} catch (MalformedURLException e){
//			logger.error(sm.getString("contextConfig.webinfClassesUrl"),e);
//		}
//
//		if (webinfClasses == null) {
//			// Nothing to do.
//			return;
//		} else if ("jar".equals(webinfClasses.getProtocol())) {
//			processAnnotationsJar(webinfClasses, null, false);
//			// removed from Tomcat 8
////		} else if ("jndi".equals(webinfClasses.getProtocol())) {
////			processAnnotationsJndi(webinfClasses, null, false);
//		} else if ("file".equals(webinfClasses.getProtocol())) {
//			try {
//				processAnnotationsFile(new File(webinfClasses.toURI()), null, false);
//			} catch (URISyntaxException e) {
//				logger.error(sm.getString("contextConfig.fileUrl", webinfClasses), e);
//			} 
//		} else {
//			logger.error(sm.getString("contextConfig.unknownUrlProtocol",
//					webinfClasses.getProtocol(), webinfClasses));
//		}
//	}
//
//	protected void processAnnotationsFile(File file, org.apache.tomcat.util.descriptor.web.WebXml fragment,
//            boolean handlesTypesOnly){
//
//		if (file.isDirectory()) {
//			String[] dirs = file.list();
//			for (String dir : dirs) {
//				processAnnotationsFile(new File(file,dir), fragment, handlesTypesOnly);
//			}
//		} else if (file.canRead() && file.getName().endsWith(".class")) {
//			FileInputStream fis = null;
//			try {
//				fis = new FileInputStream(file);
//				processAnnotationsStream(fis, fragment, handlesTypesOnly);
//			} catch (IOException e) {
//				logger.error(sm.getString("contextConfig.inputStreamFile",
//						file.getAbsolutePath()),e);
//			} finally {
//				if (fis != null) {
//					try {
//						fis.close();
//					} catch (Throwable t) {
//						ExceptionUtils.handleThrowable(t);
//					}
//				}
//			}
//		}
//	}
//
//	protected void processAnnotationsJar(URL url, org.apache.tomcat.util.descriptor.web.WebXml fragment,
//            boolean handlesTypesOnly) {
//
//		JarFile jarFile = null;
//
//		try {
//			URLConnection urlConn = url.openConnection();
//			JarURLConnection jarUrlConn;
//			if (!(urlConn instanceof JarURLConnection)) {
//				// This should never happen
//				sm.getString("contextConfig.jarUrl", url);
//				return;
//			}
//
//			jarUrlConn = (JarURLConnection) urlConn;
//			jarUrlConn.setUseCaches(false);
//			jarFile = jarUrlConn.getJarFile();
//
//			Enumeration jarEntries = jarFile.entries();
//			while (jarEntries.hasMoreElements()) {
//				JarEntry jarEntry = jarEntries.nextElement();
//				String entryName = jarEntry.getName();
//				if (entryName.endsWith(".class")) {
//					InputStream is = null;
//					try {
//						is = jarFile.getInputStream(jarEntry);
//						processAnnotationsStream(is, fragment, handlesTypesOnly);
//					} catch (IOException e) {
//						logger.error(sm.getString("contextConfig.inputStreamJar",
//								entryName, url),e);
//					} finally {
//						if (is != null) {
//							try {
//								is.close();
//							} catch (Throwable t) {
//								ExceptionUtils.handleThrowable(t);
//							}
//						}
//					}
//				}
//			}
//		} catch (IOException e) {
//			logger.error(sm.getString("contextConfig.jarFile", url), e);
//		} finally {
//			if (jarFile != null) {
//				try {
//					jarFile.close();
//				} catch (Throwable t) {
//					ExceptionUtils.handleThrowable(t);
//				}
//			}
//		}
//	}

	// removed from Tomcat 8
//	protected void processAnnotationsJndi(URL url) {
//		try {
//			URLConnection urlConn = url.openConnection();
//			DirContextURLConnection dcUrlConn;
//			if (!(urlConn instanceof DirContextURLConnection)) {
//				// This should never happen
//				sm.getString("contextConfig.jndiUrlNotDirContextConn", url);
//				return;
//			}
//
//			dcUrlConn = (DirContextURLConnection) urlConn;
//			dcUrlConn.setUseCaches(false);
//
//			String type = dcUrlConn.getHeaderField(ResourceAttributes.TYPE);
//			if (ResourceAttributes.COLLECTION_TYPE.equals(type)) {
//				// Collection
//				Enumeration dirs = dcUrlConn.list();
//				while (dirs.hasMoreElements()) {
//					String dir = dirs.nextElement();
//					URL dirUrl = new URL(url.toString() + '/' + dir);
//					processAnnotationsJndi(dirUrl);
//				}
//
//			} else {
//				// Single file
//				if (url.getPath().endsWith(".class")) {
//					InputStream is = null;
//					try {
//						is = dcUrlConn.getInputStream();
//						processAnnotationsStream(is);
//					} catch (IOException e) {
//						logger.error(sm.getString("contextConfig.inputStreamJndi",
//								url),e);
//					} finally {
//						if (is != null) {
//							try {
//								is.close();
//							} catch (Throwable t) {
//								ExceptionUtils.handleThrowable(t);
//							}
//						}
//					}
//				}
//			}
//		} catch (IOException e) {
//			logger.error(sm.getString("contextConfig.jndiUrl", url), e);
//		} 
//	}

//	protected void processAnnotationsStream(InputStream is, org.apache.tomcat.util.descriptor.web.WebXml fragment,
//            boolean handlesTypesOnly)
//	throws ClassFormatException, IOException {
//
//		ClassParser parser = new ClassParser(is);
//		JavaClass clazz = parser.parse();
//		checkHandlesTypes(clazz);
//
//        if (handlesTypesOnly) {
//            return;
//        }
//
//		AnnotationEntry[] annotationsEntries = clazz.getAnnotationEntries();
//		if (annotationsEntries != null) {
//			for (AnnotationEntry ae : annotationsEntries) {
//				String type = ae.getAnnotationType();
//				if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) {
//					hasWebAnnotations=true;
//				}else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) {
//					hasWebAnnotations=true;
//				}else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) {
//					hasWebAnnotations=true;
//				}else if ("Ljavax/servlet/annotation/WebInitParam;".equals(type)) {
//					hasWebAnnotations=true;
//				}else if ("Ljavax/servlet/annotation/MultipartConfig;".equals(type)) {
//					hasWebAnnotations=true;
//				} else {
//					// Unknown annotation - ignore
//				}
//			}
//		}
//	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy