Package org.ajax4jsf.resource

Source Code of org.ajax4jsf.resource.ResourceBuilderImpl

/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

package org.ajax4jsf.resource;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import javax.faces.FacesException;
import javax.faces.context.FacesContext;
import javax.imageio.ImageIO;
import javax.servlet.ServletContext;

import org.ajax4jsf.Messages;
import org.ajax4jsf.resource.util.URLToStreamHelper;
import org.ajax4jsf.util.base64.Codec;
import org.ajax4jsf.webapp.WebXml;
import org.apache.commons.digester.Digester;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
* Produce instances of InternetResource's for any types - jar resource, dynamic
* created image, component-incapsulated etc. Realised as singleton class to
* support cache, configuration etc.
*
* @author shura (latest modification by $Author: alexsmirnov $)
* @version $Revision: 1.1.2.1 $ $Date: 2007/01/09 18:56:58 $
*
*/
public class ResourceBuilderImpl extends InternetResourceBuilder {

  private static final Log log = LogFactory.getLog(ResourceBuilderImpl.class);

  private static final String DATA_SEPARATOR = "/DATA/";
  private static final String DATA_BYTES_SEPARATOR = "/DATB/";

  private static final Pattern DATA_SEPARATOR_PATTERN = Pattern
      .compile("/DAT(A|B)/");

  private static Map renderers;

  private static ResourceRenderer defaultRenderer = new MimeRenderer(null);

  /**
   * keep resources instances . TODO - put this map to application-scope
   * attribute, for support clastering environment.
   */
  private Map resources = Collections.synchronizedMap(new HashMap());

  private long _startTime;

  private Codec codec;

  static {
    renderers = new HashMap();
    // append known renderers for extentions.
    renderers.put(".gif", new GifRenderer());
    ResourceRenderer renderer = new JpegRenderer();
    renderers.put(".jpeg", renderer);
    renderers.put(".jpg", renderer);
    renderers.put(".png", new PngRenderer());
    renderers.put(".js", new ScriptRenderer());
    renderers.put(".css", new StyleRenderer());
    renderers.put(".log", new LogfileRenderer());
    renderers.put(".html", new HTMLRenderer());
    renderers.put(".xhtml", new MimeRenderer("application/xhtml+xml"));
    renderers.put(".xml", new MimeRenderer("text/xml"));
    renderers.put(".xcss", new TemplateCSSRenderer());
    // renderers.put(".htc",new BehaviorRenderer());
    // set in-memory caching ImageIO
    ImageIO.setUseCache(false);

  }

  public WebXml getWebXml(FacesContext context) {
    WebXml webXml = (WebXml) context.getExternalContext()
        .getApplicationMap().get(WebXml.CONTEXT_ATTRIBUTE);
    if (null == webXml) {
      throw new FacesException(
          "Resources framework is not initialised, check web.xml for Filter configuration");
    }
    return webXml;
  }

  public ResourceBuilderImpl() {
    super();
    _startTime = System.currentTimeMillis();
    codec = new Codec();
  }

  /**
   * @throws FacesException
   */
  protected void registerResources() throws FacesException {
    try {
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      Enumeration e = loader
          .getResources("META-INF/resources-config.xml");
      while (e.hasMoreElements()) {
        URL resource = (URL) e.nextElement();
        registerConfig(resource);
      }
    } catch (IOException e) {
      throw new FacesException(e);
    }
  }

  private void registerConfig(URL resourceConfig) {
    try {
      if (log.isDebugEnabled()) {
        log.debug("Process resources configuration file "
            + resourceConfig.toExternalForm());
      }

      InputStream in = URLToStreamHelper.urlToStream(resourceConfig);
      try {
        Digester digester = new Digester();
        digester.setValidating(false);
        digester.setEntityResolver(new EntityResolver() {
          // Dummi resolver - alvays do nothing
          public InputSource resolveEntity(String publicId,
              String systemId) throws SAXException, IOException {
            return new InputSource(new StringReader(""));
          }
        });
        digester.setNamespaceAware(false);
        digester.setUseContextClassLoader(true);
        digester.push(this);
        digester.addObjectCreate("resource-config/resource", "class",
            JarResource.class);
        digester.addObjectCreate("resource-config/resource/renderer",
            "class", HTMLRenderer.class);
        digester.addCallMethod(
            "resource-config/resource/renderer/content-type",
            "setContentType", 0);
        digester.addSetNext("resource-config/resource/renderer",
            "setRenderer", ResourceRenderer.class.getName());
        digester.addCallMethod("resource-config/resource/name",
            "setKey", 0);
        digester.addCallMethod("resource-config/resource/path",
            "setPath", 0);
        digester.addCallMethod("resource-config/resource/cacheable",
            "setCacheable", 0);
        digester.addCallMethod(
            "resource-config/resource/session-aware",
            "setSessionAware", 0);
        digester.addCallMethod("resource-config/resource/property",
            "setProperty", 2);
        digester.addCallParam("resource-config/resource/property/name",
            0);
        digester.addCallParam(
            "resource-config/resource/property/value", 1);
        digester.addCallMethod("resource-config/resource/content-type",
            "setContentType", 0);
        digester.addSetNext("resource-config/resource", "addResource",
            InternetResource.class.getName());
        digester.parse(in);
      } finally {
        in.close();
      }
    } catch (IOException e) {
      throw new FacesException(e);
    } catch (SAXException e) {
      throw new FacesException(e);
    }
  }

  /**
   */
  public void init() throws FacesException {
    // TODO - mace codec configurable.
    registerResources();
  }

  /**
   * Base point for creating resource. Must detect type and build appropriate
   * instance. Currently - make static resource for ordinary request, or
   * instance of class.
   *
   * @param base
   *            base object for resource ( resourcess in classpath will be get
   *            relative to it package )
   * @param path
   *            key - path to resource, resource class name etc.
   * @return
   * @throws FacesException
   */
  public InternetResource createResource(Object base, String path)
      throws FacesException {
    // TODO - detect type of resource ( for example, resources location path
    // in Skin
    try {
      return getResource(path);
    } catch (ResourceNotFoundException e) {
      try {
        return getResource(buildKey(base, path));
      } catch (ResourceNotFoundException e1) {
        if (log.isDebugEnabled()) {
          log.debug(Messages.getMessage(Messages.BUILD_RESOURCE_INFO,
              path));
        }
      }
    }
    // path - is class name ?
    InternetResource res;
    try {
      Class resourceClass = Class.forName(path);
      res = createDynamicResource(path, resourceClass);
    } catch (Exception e) {
      try {
        res = createJarResource(base, path);
      } catch (ResourceNotFoundException ex) {
        res = createStaticResource(path);
      }
      // TODO - if resource not found, create static ?
    }
    return res;
  }

  private String buildKey(Object base, String path) {
    if (path.startsWith("/")) {
      return path.substring(1);
    }
    if (null == base) {
      return path;
    }
    StringBuffer packageName = new StringBuffer(base.getClass()
        .getPackage().getName().replace('.', '/'));
    return packageName.append("/").append(path).toString();
  }

  public String getUri(InternetResource resource, FacesContext context,
      Object storeData) {
    StringBuffer uri = new StringBuffer();// ResourceServlet.DEFAULT_SERVLET_PATH).append("/");
    uri.append(resource.getKey());
    // append serialized data as Base-64 encoded request string.
    if (storeData != null) {
      try {
        byte[] objectData;
        if (storeData instanceof byte[]) {
          objectData = (byte[]) storeData;
          uri.append(DATA_BYTES_SEPARATOR);
        } else {
          ByteArrayOutputStream dataSteram = new ByteArrayOutputStream(
              1024);
          ObjectOutputStream objStream = new ObjectOutputStream(
              dataSteram);
          objStream.writeObject(storeData);
          objStream.flush();
          objStream.close();
          dataSteram.close();
          objectData = dataSteram.toByteArray();
          uri.append(DATA_SEPARATOR);
        }
        byte[] dataArray = encrypt(objectData);
        uri.append(new String(dataArray, "ISO-8859-1"));

        // / byte[] objectData = dataSteram.toByteArray();
        // / uri.append("?").append(new
        // String(Base64.encodeBase64(objectData),
        // / "ISO-8859-1"));
      } catch (Exception e) {
        // Ignore errors, log it
        log.error(Messages
            .getMessage(Messages.QUERY_STRING_BUILDING_ERROR), e);
      }
    }
    String resourceURL = getWebXml(context).getFacesResourceURL(context,
        uri.toString());// context.getApplication().getViewHandler().getResourceURL(context,uri.toString());
    if (resource.isSessionAware()) {
      resourceURL = context.getExternalContext().encodeResourceURL(
          resourceURL);
    }
    if (log.isDebugEnabled()) {
      log.debug(Messages.getMessage(Messages.BUILD_RESOURCE_URI_INFO,
          resource.getKey(), resourceURL));
    }
    return resourceURL;// context.getExternalContext().encodeResourceURL(resourceURL);

  }

  /**
   * @param key
   * @return
   */
  public InternetResource getResourceForKey(String key)
      throws ResourceNotFoundException {

    Matcher matcher = DATA_SEPARATOR_PATTERN.matcher(key);
    if (matcher.find()) {
      int data = matcher.start();
      key = key.substring(0, data);
    }

    return getResource(key);
  }

  public Object getResourceDataForKey(String key) {
    Object data = null;
    String dataString = null;
    Matcher matcher = DATA_SEPARATOR_PATTERN.matcher(key);
    if (matcher.find()) {
      if (log.isDebugEnabled()) {
        log.debug(Messages.getMessage(
            Messages.RESTORE_DATA_FROM_RESOURCE_URI_INFO, key,
            dataString));
      }
      int dataStart = matcher.end();
      dataString = key.substring(dataStart);
      byte[] objectArray = null;
      byte[] dataArray;
      try {
        dataArray = dataString.getBytes("ISO-8859-1");
        objectArray = decrypt(dataArray);
      } catch (UnsupportedEncodingException e1) {
        // default encoding always presented.
      }
      if ("B".equals(matcher.group(1))) {
        data = objectArray;
      } else {
        try {
          ObjectInputStream in = new ObjectInputStream(
              new ByteArrayInputStream(objectArray));
          data = in.readObject();
        } catch (StreamCorruptedException e) {
          log.error(Messages
              .getMessage(Messages.STREAM_CORRUPTED_ERROR), e);
        } catch (IOException e) {
          log.error(Messages
              .getMessage(Messages.DESERIALIZE_DATA_INPUT_ERROR),
              e);
        } catch (ClassNotFoundException e) {
          log
              .error(
                  Messages
                      .getMessage(Messages.DATA_CLASS_NOT_FOUND_ERROR),
                  e);
        }
      }
    }

    return data;
  }

  public InternetResource getResource(String path)
      throws ResourceNotFoundException {

    InternetResource internetResource = (InternetResource) resources
        .get(path);
    if (null == internetResource) {
      throw new ResourceNotFoundException("Resource not registered : "
          + path);
    } else {
      return internetResource;
    }
  }

  public void addResource(InternetResource resource) {
    resources.put(resource.getKey(), resource);
    ResourceRenderer renderer = resource.getRenderer(null);
    if (renderer == null) {
      setRenderer(resource, resource.getKey());
    }
  }

  public void addResource(String key, InternetResource resource) {
    resources.put(key, resource);
    resource.setKey(key);
    // TODO - set renderer ?
  }

  // public String getFacesResourceKey(HttpServletRequest request) {
  // return getWebXml(context).getFacesResourceKey(request);
  // }

  public String getFacesResourceURL(FacesContext context, String Url) {
    return getWebXml(context).getFacesResourceURL(context, Url);
  }

  /**
   * Build resource for link to static context in webapp.
   *
   * @param path
   * @return
   * @throws FacesException
   */
  protected InternetResource createStaticResource(String path)
      throws ResourceNotFoundException, FacesException {
    FacesContext context = FacesContext.getCurrentInstance();
    if (null != context) {
      if (context.getExternalContext().getContext() instanceof ServletContext) {
        ServletContext servletContext = (ServletContext) context
            .getExternalContext().getContext();
        InputStream in = servletContext.getResourceAsStream(path);
        if (null != in) {
          InternetResourceBase res = new StaticResource(path);
          setRenderer(res, path);
          res.setLastModified(new Date(getStartTime()));
          addResource(path, res);
          try {
            in.close();
          } catch (IOException e) {
          }
          return res;
        }
      }
    }
    throw new ResourceNotFoundException(Messages.getMessage(
        Messages.STATIC_RESOURCE_NOT_FOUND_ERROR, path));
  }

  private void setRenderer(InternetResource res, String path)
      throws FacesException {
    int lastPoint = path.lastIndexOf('.');
    if (lastPoint > 0) {
      String ext = path.substring(lastPoint);
      ResourceRenderer resourceRenderer = (ResourceRenderer) renderers
          .get(ext);
      if (null != resourceRenderer) {
        res.setRenderer(resourceRenderer);
      } else {
        if (log.isDebugEnabled()) {
          log.debug(Messages.getMessage(
              Messages.NO_RESOURCE_REGISTERED_ERROR_2, path,
              renderers.keySet()));
        }

        // String mimeType = servletContext.getMimeType(path);
        res.setRenderer(defaultRenderer);
      }
    }
  }

  /**
   * Create resurce to send from classpath relative to base class.
   *
   * @param base
   * @param path
   * @return
   * @throws FacesException
   */
  protected InternetResource createJarResource(Object base, String path)
      throws ResourceNotFoundException, FacesException {
    String key = buildKey(base, path);
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    if (null != loader.getResource(key)) {
      JarResource res = new JarResource(key);
      setRenderer(res, path);
      res.setLastModified(new Date(getStartTime()));
      addResource(key, res);
      return res;
    } else {
      throw new ResourceNotFoundException(Messages.getMessage(
          Messages.NO_RESOURCE_EXISTS_ERROR, key));
    }

  }

  /**
   * Create resource by instatiate given class.
   *
   * @param path
   * @param instatiate
   * @return
   */
  protected InternetResource createDynamicResource(String path,
      Class instatiate) throws ResourceNotFoundException {
    if (InternetResource.class.isAssignableFrom(instatiate)) {
      InternetResource resource;
      try {
        resource = (InternetResource) instatiate.newInstance();
        addResource(path, resource);
      } catch (Exception e) {
        String message = Messages.getMessage(
            Messages.INSTANTIATE_RESOURCE_ERROR, instatiate
                .toString());
        log.error(message, e);
        throw new ResourceNotFoundException(message, e);
      }
      return resource;
    }
    throw new FacesException(Messages
        .getMessage(Messages.INSTANTIATE_CLASS_ERROR));
  }

  /**
   * Create resource by instatiate {@link UserResource} class with given
   * properties ( or got from cache ).
   *
   * @param cacheable
   * @param session
   * @param mime
   * @return
   * @throws FacesException
   */
  public InternetResource createUserResource(boolean cacheable,
      boolean session, String mime) throws FacesException {
    String path = getUserResourceKey(cacheable, session, mime);
    InternetResource userResource;
    try {
      userResource = getResource(path);
    } catch (ResourceNotFoundException e) {
      userResource = new UserResource(cacheable, session, mime);
      addResource(path, userResource);
    }
    return userResource;
  }

  /**
   * Generate resource key for user-generated resource with given properties.
   *
   * @param cacheable
   * @param session
   * @param mime
   * @return
   */
  private String getUserResourceKey(boolean cacheable, boolean session,
      String mime) {
    StringBuffer pathBuffer = new StringBuffer(UserResource.class.getName());
    pathBuffer.append(cacheable ? "/c" : "/n");
    pathBuffer.append(session ? "/s" : "/n");
    if (null != mime) {
      pathBuffer.append('/').append(mime.hashCode());
    }
    String path = pathBuffer.toString();
    return path;
  }

  /**
   * @return Returns the startTime for application.
   */
  public long getStartTime() {
    return _startTime;
  }

  protected byte[] encrypt(byte[] src) {
    try {
      Deflater compressor = new Deflater(Deflater.BEST_SPEED);
      byte[] compressed = new byte[src.length + 100];
      compressor.setInput(src);
      compressor.finish();
      int totalOut = compressor.deflate(compressed);
      byte[] zipsrc = new byte[totalOut];
      System.arraycopy(compressed, 0, zipsrc, 0, totalOut);
      compressor.end();
      return codec.encode(zipsrc);
    } catch (Exception e) {
      throw new FacesException("Error encode resource data", e);
    }
  }

  protected byte[] decrypt(byte[] src) {
    try {
      byte[] zipsrc = codec.decode(src);
      Inflater decompressor = new Inflater();
      byte[] uncompressed = new byte[zipsrc.length * 5];
      decompressor.setInput(zipsrc);
      int totalOut = decompressor.inflate(uncompressed);
      byte[] out = new byte[totalOut];
      System.arraycopy(uncompressed, 0, out, 0, totalOut);
      decompressor.end();
      return out;
    } catch (Exception e) {
      throw new FacesException("Error decode resource data", e);
    }
  }

}
TOP

Related Classes of org.ajax4jsf.resource.ResourceBuilderImpl

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.