Package org.apache.wookie.w3c

Source Code of org.apache.wookie.w3c.W3CWidgetFactory

/*
*  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.apache.wookie.w3c;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;

import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.wookie.w3c.exceptions.BadManifestException;
import org.apache.wookie.w3c.exceptions.BadWidgetZipFileException;
import org.apache.wookie.w3c.exceptions.InvalidContentTypeException;
import org.apache.wookie.w3c.exceptions.InvalidStartFileException;
import org.apache.wookie.w3c.impl.WidgetManifestModel;
import org.apache.wookie.w3c.util.WidgetPackageUtils;

/**
* Factory for parsing W3C Widget packages (.wgt files).
*
* <p>To use the factory you MUST supply a valid output directory into which the Factory will unpack the widget. Other factory
* properties are optional.<p>
*
* <p>Factory properties:</p>
*
* <dl>
*   <dt>outputDirectory</dt>
*   <dd>The directory where the widget will be saved. The factory will expand the widget archive into this
*   directory, using the widget's identifier to generate a directory name and structure in which to place it</dd>
*   <dt>startPageProcessor</dt>
*   <dd>An implementation of the IStartPageProcessor interface. Setting this property allows you to inject a class that can pre-process
*   start pages for the widget; for example to inject javascript, tidy up HTML, insert template code etc. If this is not set,
*   no pre-processing is done by the factory.</dd>
*   <dt>locales</dt>
*   <dd>The supported locales (as BCP47 language-tags) to be processed for the widget. This determines which start files, icons, and other localized elements
*   will be processed and expanded. This is set to "en" by default</dd>
*   <dt>encodings</dt>
*   <dd>The supported encodings to be processed for the widget. This determines which custom encodings will be allowed for start files.
*   This is set to UTF-8 by default.</dd>
*   <dt>localPath</dt>
*   <dd>The base URL from which unpacked widgets will be served, e.g. "/myapp/widgets". The URLs of start files will be appended to
*   this base URL to create the widget URL. The default value of this property is "/widgets"</dd>
*   <dt>features</dt>
*   <dd>The features supported by the implementation; this should be supplied as IRIs e.g. "http://wave.google.com". The features
*   are matched against features requested by the widget; if the widget requires features that are unsupported, an Exception will be
*   thrown when parsing the widget package. The default value of this property is an empty String array.</dd>
* </dl>
*
*/
public class W3CWidgetFactory {
 
  // Get the logger
  static Logger _logger = Logger.getLogger(W3CWidgetFactory.class.getName());   
  // this value is set by the parser
  private File unzippedWidgetDirectory;
  private File outputDirectory;
  private IStartPageProcessor startPageProcessor;
  private String[] locales;
  private String localPath;
  private String[] features;
  private String[] encodings;

  /**
   * Set the features to be included when parsing widgets
   * @param features
   */
  public void setFeatures(String[] features) {
    this.features = features;
  }

  public W3CWidgetFactory(){
    // Defaults
    this.locales = new String[]{"en"};
    this.features = new String[0];
    this.localPath = "/widgets";
    this.outputDirectory = null;
    this.encodings = new String[]{"UTF-8"};
    this.startPageProcessor = new IStartPageProcessor(){
      public void processStartFile(File startFile, W3CWidget model)
          throws Exception {
      }
     
    };
  }
 
  /**
   * Set the directory to use to save widgets.
   * @param outputDirectory
   * @throws IOException if the directory does not exist
   */
  public void setOutputDirectory(final String outputDirectory) throws IOException {
    if (outputDirectory == null) throw new NullPointerException();
    File file = new File(outputDirectory);
    if (!file.exists()) throw new FileNotFoundException("the output directory does not exist");
    if (!file.canWrite()) throw new IOException("the output directory cannot be written to");
    if (!file.isDirectory()) throw new IOException("the output directory is not a folder");
    this.outputDirectory = file;
  }

  /**
   * Set the start page processor to use when parsing widgets
   * @param startPageProcessor
   */
  public void setStartPageProcessor(final IStartPageProcessor startPageProcessor) {
    this.startPageProcessor = startPageProcessor;
  }

  /**
   * Set the supported locales to be used when parsing widgets
   * @param locales
   */
  public void setLocales(final String[] locales) {
    if (locales == null) throw new NullPointerException("locales cannot be specified as Null");
    this.locales = locales;
  }

  /**
   * Set the base URL to use
   * @param localPath
   * @throws Exception
   */
  public void setLocalPath(final String localPath){
    if (localPath == null) throw new NullPointerException("local path cannot be set to Null");
    this.localPath = localPath;
  };
 
  /**
   * Parse a given ZipFile and return a W3CWidget object representing the processed information in the package.
   * The widget will be saved in the outputFolder.
   *
   * @param zipFile
   * @return the widget model
   * @throws BadWidgetZipFileException if there is a problem with the zip package
   * @throws BadManifestException if there is a problem with the config.xml manifest file in the package
   */
  public W3CWidget parse(final File zipFile) throws Exception, BadWidgetZipFileException, BadManifestException{
    if (outputDirectory == null) throw new Exception("No output directory has been set; use setOutputDirectory(File) to set the location to output widget files");
    return processWidgetPackage(zipFile);
  }
 
  /**
   * Parse a widget at a given URL and return a W3CWidget object representing the processed information in the package.
   * The widget will be saved in the outputFolder.
   * @param url
   * @return
   * @throws BadWidgetZipFileException if there is a problem with the zip package
   * @throws BadManifestException if there is a problem with the config.xml manifest file in the package
   * @throws InvalidContentTypeException if the widget has an invalid content type
   * @throws IOException if the widget cannot be downloaded
   */
  public W3CWidget parse(final URL url) throws BadWidgetZipFileException, BadManifestException, InvalidContentTypeException, IOException, Exception{
    File file = download(url,false);
    return parse(file);
  }
 
  /**
   * Parse a widget at a given URL and return a W3CWidget object representing the processed information in the package.
   * The widget will be saved in the outputFolder.
   * @param url
   * @param ignoreContentType set to true to instruct the parser to ignore invalid content type exceptions
   * @return
   * @throws BadWidgetZipFileException if there is a problem with the zip package
   * @throws BadManifestException if there is a problem with the config.xml manifest file in the package
   * @throws InvalidContentTypeException if the widget has an invalid content type
   * @throws IOException if the widget cannot be downloaded
   */
  public W3CWidget parse(final URL url, boolean ignoreContentType) throws BadWidgetZipFileException, BadManifestException, InvalidContentTypeException, IOException, Exception{
    File file = download(url,ignoreContentType);
    return parse(file);
  }
 
  /**
   * The standard MIME type for a W3C Widget
   */
  private static final String WIDGET_CONTENT_TYPE = "application/widget";
 
  /**
   * Download widget from given URL
   * @param url the URL to download
   * @param ignoreContentType if set to true, will ignore invalid content types (not application/widget)
   * @return the File downloaded
   * @throws InvalidContentTypeException
   * @throws HttpException
   * @throws IOException
   */
  private File download(URL url, boolean ignoreContentType) throws InvalidContentTypeException, HttpException, IOException {
    HttpClient client = new HttpClient();
    GetMethod method = new GetMethod(url.toString());
    client.executeMethod(method);
    String type = method.getResponseHeader("Content-Type").getValue();
    if (!ignoreContentType && !type.startsWith(WIDGET_CONTENT_TYPE)) throw new InvalidContentTypeException("Problem downloading widget: expected a content type of "+WIDGET_CONTENT_TYPE+" but received:"+type);
    File file = File.createTempFile("wookie", null);
    FileUtils.writeByteArrayToFile(file, IOUtils.toByteArray(method.getResponseBodyAsStream()));
    method.releaseConnection();
    return file;
  }

  public void setEncodings(final String[] encodings) throws Exception {
    if (encodings == null) throw new NullPointerException("Supported encodings cannot be set to null");
    if (encodings.length == 0) throw new Exception("At least one encoding must be specified");
    this.encodings = encodings;
  }

  /**
   * Process a widget package for the given zip file
   * @param zipFile
   * @return a W3CWidget representing the widget
   * @throws BadWidgetZipFileException
   * @throws BadManifestException
   */
  private W3CWidget processWidgetPackage(File zipFile) throws BadWidgetZipFileException, BadManifestException{
    ZipFile zip;
    try {
      zip = new ZipFile(zipFile);
    } catch (IOException e) {
      throw new BadWidgetZipFileException();
    }
    if (WidgetPackageUtils.hasManifest(zip)){
      try {
        // build the model
        WidgetManifestModel widgetModel = new WidgetManifestModel(WidgetPackageUtils.extractManifest(zip), locales, features, encodings, zip);                             

        // get the widget identifier
        String manifestIdentifier = widgetModel.getIdentifier();           
        // create the folder structure to unzip the zip into
        unzippedWidgetDirectory = WidgetPackageUtils.createUnpackedWidgetFolder(outputDirectory, manifestIdentifier);
        // now unzip it into that folder
        WidgetPackageUtils.unpackZip(zip, unzippedWidgetDirectory)
       
        // Iterate over all start files and update paths
        for (IContentEntity content: widgetModel.getContentList()){
          // now update the js links in the start page
          File startFile = new File(unzippedWidgetDirectory.getCanonicalPath() + File.separator + content.getSrc());
          String relativestartUrl = (WidgetPackageUtils.getURLForWidget(localPath, manifestIdentifier, content.getSrc()));          
          content.setSrc(relativestartUrl);
          if(startFile.exists() && startPageProcessor != null){   
            startPageProcessor.processStartFile(startFile, widgetModel);
         
        }
        if (widgetModel.getContentList().isEmpty()){
          throw new InvalidStartFileException("Widget has no start page");
        }
       
        // get the path to the root of the unzipped folder
        String thelocalPath = WidgetPackageUtils.getURLForWidget(localPath, manifestIdentifier, "");
        // now pass this to the model which will prepend the path to local resources (not web icons)
        widgetModel.updateIconPaths(thelocalPath);       
       
        // check to see if this widget already exists in the DB - using the ID (guid) key from the manifest
        return widgetModel;
      } catch (InvalidStartFileException e) {
        throw e;
      } catch (BadManifestException e) {
        throw e;
      } catch (Exception e){
        throw new BadManifestException(e);
      }
    }
    else{
      // no manifest file found in zip archive
      throw new BadWidgetZipFileException(); //$NON-NLS-1$
    }
  }
 
  public File getUnzippedWidgetDirectory() {
    return unzippedWidgetDirectory;
  }

}
TOP

Related Classes of org.apache.wookie.w3c.W3CWidgetFactory

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.