Package org.springframework.osgi.web.deployer.internal.util

Source Code of org.springframework.osgi.web.deployer.internal.util.Utils

/*
* Copyright 2006-2008 the original author or authors.
*
* Licensed 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.springframework.osgi.web.deployer.internal.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.springframework.osgi.service.importer.support.ImportContextClassLoader;
import org.springframework.osgi.service.importer.support.OsgiServiceProxyFactoryBean;
import org.springframework.osgi.util.BundleDelegatingClassLoader;
import org.springframework.osgi.util.OsgiStringUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;

/**
* Utility class for IO operations regarding web integration.
*
* @author Costin Leau
*/
public abstract class Utils {

  /** logger */
  private static final Log log = LogFactory.getLog(Utils.class);

  private static final String SLASH = "/";


  // might have to improve this method to cope with missing folder entries ...

  /**
   * Copies the given bundle content to the given target folder. This means
   * unpacking the bundle archive. In case of a failure, an exception is
   * thrown.
   *
   * @param bundle
   * @param targetFolder
   */
  public static void unpackBundle(Bundle bundle, File targetFolder) {
    // no need to use a recursive method since we get all resources directly
    Enumeration enm = bundle.findEntries(SLASH, null, true);
    while (enm != null && enm.hasMoreElements()) {
      boolean trace = log.isTraceEnabled();

      // get only the path
      URL url = (URL) enm.nextElement();
      String entryPath = url.getPath();
      if (entryPath.startsWith(SLASH))
        entryPath = entryPath.substring(1);

      File targetFile = new File(targetFolder, entryPath);
      // folder are a special case, we have to create them rather then copy
      if (entryPath.endsWith("/"))
        targetFile.mkdir();
      else {
        try {
          OutputStream targetStream = new FileOutputStream(targetFile);
          if (trace)
            log.trace("Copying " + url + " to " + targetFile);
          FileCopyUtils.copy(url.openStream(), targetStream);
        }
        catch (IOException ex) {
          //
          log.error("Cannot copy resource " + entryPath, ex);
          throw (RuntimeException) new IllegalStateException("IO exception while unpacking bundle "
              + OsgiStringUtils.nullSafeNameAndSymName(bundle)).initCause(ex);
        }
        // no need to close the streams - the utils already handles that
      }
    }
  }

  /**
   * Dedicated utility method used for creating an OSGi reference to
   * Jetty/Tomcat/XXX server service.
   *
   * @return proxy to the found OSGi service
   */
  public static Object createServerServiceProxy(BundleContext bundleContext, Class proxyType, String serviceName) {

    OsgiServiceProxyFactoryBean proxyFB = new OsgiServiceProxyFactoryBean();
    proxyFB.setBundleContext(bundleContext);
    proxyFB.setContextClassLoader(ImportContextClassLoader.UNMANAGED);
    proxyFB.setInterfaces(new Class[] { proxyType });
    // use the spring-dm class loader to generate the proxy (since it can see all the needed server classes)
    proxyFB.setBeanClassLoader(proxyType.getClassLoader());
    // wait 5 seconds
    proxyFB.setTimeout(5 * 1000);
    if (StringUtils.hasText(serviceName))
      proxyFB.setServiceBeanName(serviceName);
    proxyFB.afterPropertiesSet();

    return proxyFB.getObject();
  }

  /**
   * Detects the Jasper/JSP parser (used by the server) and returns a chained
   * class-loader which incorporates them all. This allows the web application
   * to use servlets and JSP w/o importing them (just like in traditional
   * environments).
   *
   * @return chained classloader containing javax. packages and the sever
   * classes + Jasper/JSP compiler (if present)
   */
  public static ClassLoader chainedWebClassLoaders(Class serverClass) {
    Assert.notNull(serverClass);
    ClassLoader serverLoader = serverClass.getClassLoader();
    ClassLoader jasperLoader = findClassLoaderFor(JasperUtils.JASPER_CLASS, serverLoader);

    // the server class does not import Jasper, use the web bundle instead
    if (jasperLoader == null) {
      // use the extender classloader
      jasperLoader = findClassLoaderFor(JasperUtils.JASPER_CLASS, Utils.class.getClassLoader());
    }

    // Jasper cannot be found, assume it's not installed
    if (jasperLoader == null)
      return serverLoader;
    // chain Jasper CL after the server class loader
    else {
      return new ChainedClassLoader(new ClassLoader[] { serverLoader, jasperLoader });
    }
  }

  /**
   * Returns the defining classloader of the given class. This method will
   * load the class through the given classloader but will return the class
   * actual class loader (as in OSGi, a classloader can load classes using
   * other loaders).
   *
   * @param className class to load
   * @param ClassLoader loader used to load the class (which might contain a
   * needed import)
   * @return class actual classloader - null if returned, if the class cannot
   * be loaded
   */
  private static ClassLoader findClassLoaderFor(String className, ClassLoader classLoader) {
    try {
      Class clazz = ClassUtils.forName(className, classLoader);
      return clazz.getClassLoader();
    }
    catch (Exception ex) {
      return null;
    }
  }

  /**
   * Creates an URLClassLoader for the given bundle running inside the server
   * defined by the given class. This method might create a chained
   * classloader suitable for loading server classes, javax.servlet as well as
   * compiling JSPs if Jasper is present.
   *
   * @param bundle bundle backing the webapp
   * @param serverClass class defining the container running the webapp
   * @return an URLClassLoader suitable for loading the web app classes.
   */
  public static URLClassLoader createWebAppClassLoader(Bundle bundle, Class serverClass) {
    // create a chained classloader for server classes (like Jasper)
    ClassLoader serverClassLoader = chainedWebClassLoaders(serverClass);
    // hook that with the bundle
    ClassLoader classLoader = BundleDelegatingClassLoader.createBundleClassLoaderFor(bundle, serverClassLoader);
    // create classloader suitable for Jasper
    URLClassLoader urlClassLoader = JasperUtils.createJasperClassLoader(bundle, classLoader);
    return urlClassLoader;
  }

}
TOP

Related Classes of org.springframework.osgi.web.deployer.internal.util.Utils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.