You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by Cassie <do...@apache.org> on 2008/02/08 02:33:28 UTC

Re: svn commit: r619684 - in /incubator/shindig/trunk: features/core/ java/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ java/gadgets/src/main/webapp/WEB-INF/ java/gadgets/

Just a quick thought - did you test the samplecontainer? It seems like
moving things into /files might affect it.
Thanks.

- Cassie


On Thu, Feb 7, 2008 at 3:18 PM, <et...@apache.org> wrote:

> Author: etnu
> Date: Thu Feb  7 15:18:30 2008
> New Revision: 619684
>
> URL: http://svn.apache.org/viewvc?rev=619684&view=rev
> Log:
> - Merged in changes from SHINDIG-51 and prepared code for merging
> SHINDIG-35
> - Fixed caching behavior in JsServlet; files will now be cached
> indefinitely and a cache busting token must be appended to get the new
> version.
> - Added placeholder for RpcServlet for SHINDIG-25.
> - Fixed static files path in pom.xml to be compatible with the jar-based
> build (no longer places all files into the root; now files are in
> /gadgets/files/). This may
>  require updating some of the static files, but currently examples all
> seem to work.
> - Cleaned up a spec deviation in gadgets.io (did not properly handle
> POST_DATA) and collapsed "enums" to their simplest form.
>
>
> Added:
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java
> Modified:
>    incubator/shindig/trunk/features/core/io.js
>    incubator/shindig/trunk/java/gadgets/pom.xml
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
>    incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml
>
>  incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
>
> Modified: incubator/shindig/trunk/features/core/io.js
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/io.js?rev=619684&r1=619683&r2=619684&view=diff
>
> ==============================================================================
> --- incubator/shindig/trunk/features/core/io.js (original)
> +++ incubator/shindig/trunk/features/core/io.js Thu Feb  7 15:18:30 2008
> @@ -82,37 +82,37 @@
>       case "FEED":
>         resp.data = gadgets.json.parse(resp.text);
>         if (!resp.data) {
> -          resp.errors = ["failed to parse JSON"];
> +          resp.errors.push("failed to parse JSON");
>           resp.data = null;
>         }
>         break;
> -     case "DOM":
> -      var dom;
> -      if (window.ActiveXObject) {
> -        dom = new ActiveXObject("Microsoft.XMLDOM");
> -        dom.async = false;
> -        dom.validateOnParse = false;
> -        dom.resolveExternals = false;
> -        if (!dom.loadXML(resp.text)) {
> -          resp.errors = ["failed to parse XML"];
> +      case "DOM":
> +        var dom;
> +        if (window.ActiveXObject) {
> +          dom = new ActiveXObject("Microsoft.XMLDOM");
> +          dom.async = false;
> +          dom.validateOnParse = false;
> +          dom.resolveExternals = false;
> +          if (!dom.loadXML(resp.text)) {
> +            resp.errors.push("failed to parse XML");
> +          } else {
> +            resp.data = dom;
> +          }
>         } else {
> -          resp.data = dom;
> +          var parser = new DOMParser();
> +          dom = parser.parseFromString(resp.text, "text/xml");
> +          if ("parsererror" == dom.documentElement.nodeName) {
> +            resp.errors.push("failed to parse XML");
> +          } else {
> +            resp.data = dom;
> +          }
>         }
> -      } else {
> -        var parser = new DOMParser();
> -        dom = parser.parseFromString(resp.text, "text/xml");
> -        if ("parsererror" == dom.documentElement.nodeName) {
> -          resp.errors = ["failed to parse XML"];
> -        } else {
> -          resp.data = dom;
> -        }
> -      }
> -      break;
> -    default:
> -      resp.data = resp.text;
> -      break;
> -   }
> -   callback(resp);
> +        break;
> +      default:
> +        resp.data = resp.text;
> +        break;
> +    }
> +    callback(resp);
>   }
>
>   return /** @scope gadgets.io */ {
> @@ -145,10 +145,8 @@
>           encodeURIComponent(url));
>
>       // Check if authorization is requested
> -      if (opt_params && opt_params.AUTHORIZATION &&
> -          gadgets.io.AuthorizationType
> [opt_params.AUTHORIZATION.toUpperCase()]
> -              != gadgets.io.AuthorizationType.NONE) {
> -        newUrl += "&authz=" + opt_params.AUTHORIZATION.toLowerCase();
> +      if (params.AUTHORIZATION && params.AUTHORIZATION !== "NONE") {
> +        newUrl += "&authz=" + params.AUTHORIZATION.toLowerCase();
>         // Add the security-token if available
>         if (gadgets.util.getUrlParameters()["st"]) {
>           newUrl += "&st=" + gadgets.util.getUrlParameters()["st"];
> @@ -160,10 +158,11 @@
>         xhr.onreadystatechange = gadgets.util.makeClosure(null,
>             processResponse, url, callback, params, xhr);
>       }
> -      if (params.METHOD == "POST") {
> -        xhr.setRequestHeader('Content-Type',
> 'application/x-www-form-urlencoded');
> -        if (params.postData) {
> -          xhr.send("postData=" + encodeURIComponent(params.postData));
> +      if (params.METHOD === "POST") {
> +        xhr.setRequestHeader('Content-Type',
> +            'application/x-www-form-urlencoded');
> +        if (params.POST_DATA) {
> +          xhr.send("postData=" + encodeURIComponent(params.POST_DATA));
>         } else {
>           xhr.send("postData=");
>         }
> @@ -225,189 +224,25 @@
>   };
>  }();
>
> -// TODO: This can all be removed after the spec is published. This is
> only
> -// here to satisfy documentation requirements.
> -
> -/**
> - * @static
> - * @class
> - * Used by the
> - * <a href="gadgets.io.html#makeRequest">
> - * <code>gadgets.io.makeRequest()</code></a> method.
> - * @name gadgets.io.RequestParameters
> - */
> -gadgets.io.RequestParameters = {
> -  /**
> -   * The method to use when fetching content from the URL;
> -   * defaults to <code>MethodType.GET</a></code>.
> -   * Specified as a
> -   * <a href="gadgets.io.MethodType.html">MethodType</a>.
> -   *
> -   * @member gadgets.io.RequestParameters
> -   */
> -   METHOD : 'METHOD',
> -
> -  /**
> -   * The type of content that lives at the URL;
> -   * defaults to <code>ContentType.HTML</code>.
> -   * Specified as a
> -   * <a href="gadgets.io.ContentType.html">
> -   * ContentType</a>.
> -   *
> -   * @member gadgets.io.RequestParameters
> -   */
> -  CONTENT_TYPE : "CONTENT_TYPE",
> -
> -  /**
> -   * The data to send to the URL using the POST method;
> -   * defaults to null.
> -   * Specified as a <code>String</code>.
> -   *
> -   * @member gadgets.io.RequestParameters
> -   */
> -  POST_DATA : "POST_DATA",
> -
> -  /**
> -   * The HTTP headers to send to the URL;
> -   * defaults to null.
> -   * Specified as a <code>Map.&lt;String,String&gt;</code>.
> -   *
> -   * @member gadgets.io.RequestParameters
> -   */
> -  HEADERS : "HEADERS",
> -
> -  /**
> -   * The type of authentication to use when fetching the content;
> -   * defaults to <code>AuthorizationType.NONE</code>.
> -   * Specified as an
> -   * <a href="gadgets.io.AuthorizationType.html">
> -   * AuthorizationType</a>.
> -   *
> -   * @member gadgets.io.RequestParameters
> -   */
> -  AUTHORIZATION : 'AUTHORIZATION',
> -
> -
> -  /**
> -   * If the content is a feed, the number of entries to fetch;
> -   * defaults to 3.
> -   * Specified as a <code>Number</code>.
> -   *
> -   * @member gadgets.io.RequestParameters
> -   */
> -  NUM_ENTRIES : 'NUM_ENTRIES',
> -
> -  /**
> -   * If the content is a feed, whether to fetch summaries for that feed;
> -   * defaults to false.
> -   * Specified as a <code>Boolean</code>.
> -   *
> -   * @member gadgets.io.RequestParameters
> -   */
> -  GET_SUMMARIES : 'GET_SUMMARIES'
> -};
> -
> -
> -/**
> - * @static
> - * @class
> - * Used by
> - * <a href="gadgets.io.RequestParameters.html">
> - * RequestParameters</a>.
> - * @name gadgets.io.MethodType
> - */
> -gadgets.io.MethodType = {
> -  /**
> -   * The default type.
> -   * @member gadgets.io.MethodType
> -   */
> -  GET : 'GET',
> -
> -  /**
> -   * Not supported by all containers.
> -   * @member gadgets.io.MethodType
> -   */
> -  POST : 'POST',
> -
> -  /**
> -   * Not supported by all containers.
> -   * @member gadgets.io.MethodType
> -   */
> -  PUT : 'PUT',
> -
> -  /**
> -   * Not supported by all containers.
> -   * @member gadgets.io.MethodType
> -   */
> -  DELETE : 'DELETE',
> -
> -  /**
> -   * Not supported by all containers.
> -   * @member gadgets.io.MethodType
> -   */
> -  HEAD : 'HEAD'
> -};
> -
> -
> -/**
> - * @static
> - * @class
> - * Used by
> - * <a href="gadgets.io.RequestParameters.html">
> - * RequestParameters</a>.
> - * @name gadgets.io.ContentType
> - */
> -gadgets.io.ContentType = {
> -  /**
> -   * Returns text; used for fetching HTML.
> -   * @member gadgets.io.ContentType
> -   */
> -  TEXT : 'TEXT',
> -
> -  /**
> -   * Returns a DOM object; used for fetching XML.
> -   * @member gadgets.io.ContentType
> -   */
> -  DOM : 'DOM',
> -
> -  /**
> -   * Returns a JSON object.
> -   * @member gadgets.io.ContentType
> -   */
> -  JSON : 'JSON',
> -
> -  /**
> -   * Returns a JSON representation of a feed.
> -   * @member gadgets.io.ContentType
> -   */
> -  FEED : 'FEED'
> -};
> -
> -
> -/**
> - * @static
> - * @class
> - * Used by
> - * <a href="gadgets.io.RequestParameters.html">
> - * RequestParameters</a>.
> - * @name gadgets.io.AuthorizationType
> - */
> -gadgets.io.AuthorizationType = {
> -  /**
> -   * No authorization.
> -   * @member gadgets.io.AuthorizationType
> -   */
> -  NONE : 'NONE',
> -
> -  /**
> -   * The request will be signed by the container.
> -   * @member gadgets.io.AuthorizationType
> -   */
> -  SIGNED : 'SIGNED',
> -
> -  /**
> -   * The container will use full authentication.
> -   * @member gadgets.io.AuthorizationType
> -   */
> -  AUTHENTICATED : 'AUTHENTICATED'
> -};
> +gadgets.io.RequestParameters = gadgets.util.makeEnum([
> +  "METHOD",
> +  "CONTENT_TYPE",
> +  "POST_DATA",
> +  "HEADERS",
> +  "AUTHORIZATION",
> +  "NUM_ENTRIES",
> +  "GET_SUMMARIES"
> +]);
> +
> +// PUT, DELETE, and HEAD not supported currently.
> +gadgets.io.MethodType = gadgets.util.makeEnum([
> +  "GET", "POST", "PUT", "DELETE", "HEAD"
> +]);
> +
> +gadgets.io.ContentType = gadgets.util.makeEnum([
> +  "TEXT", "DOM", "JSON", "FEED"
> +]);
> +
> +gadgets.io.AuthorizationType = gadgets.util.makeEnum([
> +  "NONE", "SIGNED", "AUTHENTICATED"
> +]);
> \ No newline at end of file
>
> Modified: incubator/shindig/trunk/java/gadgets/pom.xml
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/pom.xml?rev=619684&r1=619683&r2=619684&view=diff
>
> ==============================================================================
> --- incubator/shindig/trunk/java/gadgets/pom.xml (original)
> +++ incubator/shindig/trunk/java/gadgets/pom.xml Thu Feb  7 15:18:30 2008
> @@ -28,6 +28,7 @@
>             <resource>
>               <!-- this is relative to the pom.xml directory -->
>               <directory>../../javascript/</directory>
> +              <targetPath>files</targetPath>
>               <includes>
>                 <include>**/*.*</include>
>               </includes>
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java?rev=619684&r1=619683&r2=619684&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java
> Thu Feb  7 15:18:30 2008
> @@ -146,6 +146,13 @@
>   }
>
>   /**
> +   * @return All registered features.
> +   */
> +  public Map<String, Entry> getAllFeatures() {
> +    return Collections.unmodifiableMap(features);
> +  }
> +
> +  /**
>    * Attempts to retrieve all the {@code GadgetFeature} classes specified
>    * in the {@code needed} list. Those that are found are returned in
>    * {@code resultsFound}, while the names of those that are missing are
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java?rev=619684&r1=619683&r2=619684&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
> Thu Feb  7 15:18:30 2008
> @@ -22,39 +22,21 @@
>  import java.net.MalformedURLException;
>  import java.util.ArrayList;
>  import java.util.Arrays;
> +import java.util.Collections;
>  import java.util.HashSet;
>  import java.util.LinkedList;
>  import java.util.List;
>  import java.util.Locale;
>  import java.util.Map;
>  import java.util.Set;
> -import java.util.Collections;
>  import java.util.concurrent.Callable;
>  import java.util.concurrent.CompletionService;
>  import java.util.concurrent.ExecutionException;
> -import java.util.concurrent.Executor;
>  import java.util.concurrent.ExecutorCompletionService;
>  import java.util.concurrent.Future;
> -import java.util.logging.Logger;
> -import java.util.logging.Level;
>
>  public class GadgetServer {
> -  private final GadgetServerConfig config;
> -
> -  private static final Logger logger
> -      = Logger.getLogger("org.apache.shindig.gadgets");
> -
> -  /**
> -   * Creates a GadgetServer without a config.
> -   *
> -   * @deprecated Replaced by {@link
> #GadgetServer(GadgetServerConfigReader)}.
> -   * @param executor
> -   */
> -  @Deprecated
> -  public GadgetServer(Executor executor) {
> -    config = new GadgetServerConfig();
> -    config.setExecutor(executor);
> -  }
> +  private final GadgetServerConfigReader config;
>
>   /**
>    * Creates a GadgetServer using the provided configuration.
> @@ -72,51 +54,11 @@
>     Check.notNull(configuration.getContentFetcher(),
>         "ContentFetcher is required.");
>
> -    config = new GadgetServerConfig();
> +    config = new GadgetServerConfigReader();
>     config.copyFrom(configuration);
>   }
>
>   /**
> -   * @deprecated Replaced by {@link
> #GadgetServer(GadgetServerConfigReader)}.
> -   */
> -  @Deprecated
> -  public void setSpecCache(GadgetDataCache<GadgetSpec> specCache) {
> -    config.setSpecCache(specCache);
> -  }
> -
> -  /**
> -   * @deprecated Replaced by {@link
> #GadgetServer(GadgetServerConfigReader)}.
> -   */
> -  @Deprecated
> -  public void setMessageBundleCache(GadgetDataCache<MessageBundle> cache)
> {
> -    config.setMessageBundleCache(cache);
> -  }
> -
> -  /**
> -   * @deprecated Replaced by {@link
> #GadgetServer(GadgetServerConfigReader)}.
> -   */
> -  @Deprecated
> -  public void setContentFetcher(RemoteContentFetcher fetcher) {
> -    config.setContentFetcher(fetcher);
> -  }
> -
> -  /**
> -   * @deprecated Replaced by {@link
> #GadgetServer(GadgetServerConfigReader)}.
> -   */
> -  @Deprecated
> -  public void setGadgetFeatureRegistry(GadgetFeatureRegistry registry) {
> -    config.setFeatureRegistry(registry);
> -  }
> -
> -  /**
> -   * @deprecated Replaced by {@link
> #GadgetServer(GadgetServerConfigReader)}.
> -   */
> -  @Deprecated
> -  public void setGadgetBlacklist(GadgetBlacklist gadgetBlacklist) {
> -    config.setGadgetBlacklist(gadgetBlacklist);
> -  }
> -
> -  /**
>    * @return A read-only view of the server's configuration.
>    */
>   public GadgetServerConfigReader getConfig() {
> @@ -140,22 +82,6 @@
>                               RenderingContext rctx,
>                               ProcessingOptions options)
>       throws GadgetProcessException {
> -    // TODO: Remove dep checks when GadgetServer(Executor) is removed.
> -    if (config.getSpecCache() == null) {
> -      throw new GadgetProcessException(
> GadgetException.Code.MISSING_SPEC_CACHE);
> -    }
> -    if (config.getMessageBundleCache() == null ) {
> -      throw new GadgetProcessException(
> -          GadgetException.Code.MISSING_MESSAGE_BUNDLE_CACHE);
> -    }
> -    if (config.getContentFetcher() == null) {
> -      throw new GadgetProcessException(
> -          GadgetException.Code.MISSING_REMOTE_OBJECT_FETCHER);
> -    }
> -    if (config.getFeatureRegistry() == null) {
> -      throw new GadgetProcessException(
> -          GadgetException.Code.MISSING_FEATURE_REGISTRY);
> -    }
>
>     // Queue/tree of all jobs to be run for successful processing
>     GadgetContext gc = new GadgetContext(config.getContentFetcher(),
> @@ -242,8 +168,6 @@
>       }
>
>       if (gadgetException != null) {
> -        logger.log(Level.SEVERE, gadgetException.getCode().toString(),
> gadgetException);
> -
>         // Add to list of all exceptions caught, clear jobs, and continue
>         // to aggressively catch as many exceptions as possible. Since
>         // tasks are running anyway, we may as well get their results in
> @@ -320,7 +244,8 @@
>
>     private WorkflowContext(GadgetContext context) {
>       this.context = context;
> -      this.depsDone = Collections.synchronizedSet(new
> HashSet<WorkflowDependency>());
> +      this.depsDone
> +          = Collections.synchronizedSet(new
> HashSet<WorkflowDependency>());
>       this.jobsToRun = new WorkflowJobList(this);
>     }
>   }
> @@ -431,8 +356,9 @@
>       Map<String, GadgetSpec.FeatureSpec> requires = wc.gadget.getRequires
> ();
>       Set<String> needed = new HashSet<String>(requires.size());
>       Set<String> optionalNames = new HashSet<String>();
> -
> -      for (Map.Entry<String, GadgetSpec.FeatureSpec> entry :
> requires.entrySet()) {
> +
> +      for (Map.Entry<String, GadgetSpec.FeatureSpec> entry :
> +        requires.entrySet()) {
>         needed.add(entry.getKey());
>         if (entry.getValue().isOptional()) {
>           optionalNames.add(entry.getKey());
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java?rev=619684&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
> Thu Feb  7 15:18:30 2008
> @@ -0,0 +1,107 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.shindig.gadgets.http;
> +
> +import org.apache.shindig.gadgets.Gadget;
> +import org.apache.shindig.gadgets.GadgetServer;
> +import org.apache.shindig.gadgets.GadgetSigner;
> +
> +import java.util.logging.Logger;
> +
> +import javax.servlet.ServletConfig;
> +import javax.servlet.ServletContext;
> +import javax.servlet.ServletException;
> +import javax.servlet.http.HttpServletRequest;
> +
> +/**
> + * Loads shared configuration and creates appropriate class instances for
> + * sharing amongst servlets.
> + */
> +public abstract class CrossServletState {
> +  private static final Logger logger
> +      = Logger.getLogger("org.apache.shindig.gadgets");
> +  /**
> +   * @param config
> +   * @return A CrossServletState appropriate for the given ServletConfig
> +   * @throws ServletException
> +   */
> +  public static synchronized CrossServletState get(ServletConfig config)
> +      throws ServletException {
> +    ServletContext context = config.getServletContext();
> +    // Check to see if the context has already been created. If it has,
> +    // just return.
> +    CrossServletState state
> +        = (CrossServletState)context.getAttribute("servlet-data");
> +
> +    if (state == null) {
> +      String dataClass = context.getInitParameter("servlet-data-class");
> +      if (dataClass  == null) {
> +        throw new ServletException("servlet-data-class is missing.");
> +      }
> +      logger.info("Loading CrossServletState: " + dataClass);
> +      try {
> +        state  =
> (CrossServletState)Class.forName(dataClass).newInstance();
> +        state.init(context);
> +        context.setAttribute("servlet-data", state);
> +      } catch (InstantiationException ie) {
> +        throw new ServletException(ie);
> +      } catch (IllegalAccessException iae) {
> +        throw new ServletException(iae);
> +      } catch (ClassNotFoundException cnfe) {
> +        throw new ServletException(cnfe);
> +      }
> +    }
> +    return state;
> +  }
> +
> +  /**
> +   * @return A GadgetServer instance that is fully configured and
> +   * ready to be used to process gadgets.
> +   */
> +  public abstract GadgetServer getGadgetServer();
> +
> +  /**
> +   * @param req The request that a signing token is needed for.
> +   * @return A unique GadgetSigner for the request
> +   */
> +  public abstract GadgetSigner getGadgetSigner(HttpServletRequest req);
> +
> +  /**
> +   * Constructs a url for retrieving javascript for the given
> +   * set of features.
> +   *
> +   * @param features
> +   * @return The url to retrieve the appropriate JS.
> +   */
> +  public abstract String getJsUrl(String[] features);
> +
> +  /**
> +   * Constructs a url for generating an iframe for the given gadget.
> +   * This only applies for RPC calls that must generate an iframe.
> +   */
> +  public abstract String getIframeUrl(Gadget gadget,  HttpServletRequest
> req);
> +
> +  /**
> +   * Initializes this handler using the provided implementation.
> +   * @param context
> +   * @throws ServletException
> +   */
> +  protected abstract void init(ServletContext context) throws
> ServletException;
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java?rev=619684&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
> Thu Feb  7 15:18:30 2008
> @@ -0,0 +1,192 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.shindig.gadgets.http;
> +
> +import org.apache.shindig.gadgets.BasicGadgetDataCache;
> +import org.apache.shindig.gadgets.BasicGadgetSigner;
> +import org.apache.shindig.gadgets.BasicRemoteContentFetcher;
> +import org.apache.shindig.gadgets.Gadget;
> +import org.apache.shindig.gadgets.GadgetException;
> +import org.apache.shindig.gadgets.GadgetFeatureFactory;
> +import org.apache.shindig.gadgets.GadgetFeatureRegistry;
> +import org.apache.shindig.gadgets.GadgetServer;
> +import org.apache.shindig.gadgets.GadgetServerConfig;
> +import org.apache.shindig.gadgets.GadgetSigner;
> +import org.apache.shindig.gadgets.GadgetSpec;
> +import org.apache.shindig.gadgets.JsLibrary;
> +import org.apache.shindig.gadgets.JsLibraryFeatureFactory;
> +import org.apache.shindig.gadgets.MessageBundle;
> +import org.apache.shindig.gadgets.RenderingContext;
> +
> +import java.io.UnsupportedEncodingException;
> +import java.net.URLEncoder;
> +import java.security.MessageDigest;
> +import java.security.NoSuchAlgorithmException;
> +import java.util.Map;
> +import java.util.concurrent.Executors;
> +
> +import javax.servlet.ServletContext;
> +import javax.servlet.ServletException;
> +import javax.servlet.http.HttpServletRequest;
> +
> +/**
> + * A handler which uses all of the basic versions of classes.
> + */
> +public class DefaultCrossServletState extends CrossServletState {
> +
> +  private GadgetServer gadgetServer;
> +  private GadgetSigner gadgetSigner;
> +  private String jsPath;
> +  private String iframePath;
> +  private String jsCacheParam;
> +
> +  private static final String DEFAULT_JS_PREFIX = "/gadgets/js/";
> +  private static final String DEFAULT_IFRAME_PREFIX  = "/gadgets/ifr?";
> +
> +  /**
> +   * {@inheritDoc}
> +   */
> +  @Override
> +  public GadgetServer getGadgetServer() {
> +    return gadgetServer;
> +  }
> +
> +  /**
> +   * {@inheritDoc}
> +   * Just returns the same gadget signer no matter the request.
> +   */
> +  @Override
> +  public GadgetSigner getGadgetSigner(HttpServletRequest req) {
> +    return gadgetSigner;
> +  }
> +
> +  /**
> +   * {@inheritDoc}
> +   */
> +  @Override
> +  public String getIframeUrl(Gadget gadget, HttpServletRequest req) {
> +    // We don't have any meaningful data in the current request anyway,
> so
> +    // we'll just do this statically.
> +    StringBuilder buf = new StringBuilder();
> +    try {
> +      buf.append(iframePath)
> +          .append("url=")
> +          .append(
> +              URLEncoder.encode(gadget.getId
> ().getURI().toString(),"UTF-8"));
> +    } catch (UnsupportedEncodingException e) {
> +      throw new RuntimeException("UTF-8 Not supported!", e);
> +    }
> +
> +    // TODO: extract user prefs, current view, etc. from <req>. Currently
> +    // consumers of the response are on their own for this.
> +    return buf.toString();
> +  }
> +
> +  /**
> +   * {@inheritDoc}
> +   */
> +  @Override
> +  public String getJsUrl(String[] features) {
> +    StringBuilder buf = new StringBuilder();
> +    buf.append(jsPath);
> +    if (features == null || features.length == 0) {
> +      buf.append("core");
> +    } else {
> +      boolean firstDone = false;
> +      for (String feature : features) {
> +        if (firstDone) {
> +          buf.append(":");
> +        } else {
> +          firstDone = true;
> +        }
> +        buf.append(feature);
> +      }
> +    }
> +    buf.append(".js?v=").append(jsCacheParam);
> +    return buf.toString();
> +  }
> +
> +  /**
> +   * {@inheritDoc}
> +   */
> +  @Override
> +  protected void init(ServletContext context) throws ServletException {
> +    jsPath = context.getInitParameter("js-service-path");
> +    if (jsPath == null) {
> +      jsPath = DEFAULT_JS_PREFIX;
> +    }
> +
> +    iframePath = context.getInitParameter("iframe-path");
> +    if (iframePath == null) {
> +      iframePath = DEFAULT_IFRAME_PREFIX;
> +    }
> +
> +    // features could be null, but that would probably be a bad idea.
> +    String features = context.getInitParameter("features");
> +    try {
> +      gadgetSigner = new BasicGadgetSigner();
> +      GadgetFeatureRegistry registry = new
> GadgetFeatureRegistry(features);
> +      GadgetServerConfig config =  new GadgetServerConfig()
> +          .setExecutor(Executors.newCachedThreadPool())
> +          .setMessageBundleCache(new
> BasicGadgetDataCache<MessageBundle>())
> +          .setSpecCache(new BasicGadgetDataCache<GadgetSpec>())
> +          .setContentFetcher(new BasicRemoteContentFetcher(1024 * 1024))
> +          .setFeatureRegistry(registry);
> +      gadgetServer = new GadgetServer(config);
> +
> +      // Grab all static javascript, concatenate it together, and
> generate
> +      // an md5. This becomes the cache busting suffix for javascript
> files.
> +      StringBuilder jsBuf = new StringBuilder();
> +
> +      for (Map.Entry<String, GadgetFeatureRegistry.Entry> entry :
> +          registry.getAllFeatures().entrySet()) {
> +        GadgetFeatureFactory factory = entry.getValue().getFeature();
> +        if (factory instanceof JsLibraryFeatureFactory) {
> +          JsLibraryFeatureFactory lib = (JsLibraryFeatureFactory)factory;
> +          for (RenderingContext rc : RenderingContext.values()) {
> +            for (JsLibrary library : lib.getLibraries(rc)) {
> +              jsBuf.append(library.getContent());
> +            }
> +          }
> +        }
> +      }
> +      MessageDigest md;
> +      try {
> +        md = MessageDigest.getInstance("MD5");
> +      } catch (NoSuchAlgorithmException noMD5) {
> +        try {
> +          md = MessageDigest.getInstance("SHA");
> +        } catch (NoSuchAlgorithmException noSha) {
> +          throw new ServletException("No suitable MessageDigest found!");
> +        }
> +      }
> +      byte[] hash = md.digest(jsBuf.toString().getBytes());
> +      // Convert to hex. This might be a waste of bytes (32) -- could be
> +      // replaced with a base64 implementation.
> +      StringBuffer hexString = new StringBuffer();
> +      for (byte b : hash) {
> +        hexString.append(Integer.toHexString(0xFF & b));
> +      }
> +      jsCacheParam = hexString.toString();
> +    } catch (GadgetException e) {
> +      throw new ServletException(e);
> +    }
> +  }
> +}
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java?rev=619684&r1=619683&r2=619684&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java
> Thu Feb  7 15:18:30 2008
> @@ -13,18 +13,13 @@
>  */
>  package org.apache.shindig.gadgets.http;
>
> -import org.apache.shindig.gadgets.BasicGadgetDataCache;
> -import org.apache.shindig.gadgets.BasicRemoteContentFetcher;
>  import org.apache.shindig.gadgets.Gadget;
>  import org.apache.shindig.gadgets.GadgetContentFilter;
>  import org.apache.shindig.gadgets.GadgetException;
> -import org.apache.shindig.gadgets.GadgetFeatureRegistry;
>  import org.apache.shindig.gadgets.GadgetServer;
> -import org.apache.shindig.gadgets.GadgetServerConfig;
>  import org.apache.shindig.gadgets.GadgetSpec;
>  import org.apache.shindig.gadgets.GadgetView;
>  import org.apache.shindig.gadgets.JsLibrary;
> -import org.apache.shindig.gadgets.MessageBundle;
>  import org.apache.shindig.gadgets.ProcessingOptions;
>  import org.apache.shindig.gadgets.RenderingContext;
>  import org.apache.shindig.gadgets.UserPrefs;
> @@ -39,11 +34,11 @@
>  import java.util.LinkedList;
>  import java.util.List;
>  import java.util.Map;
> -import java.util.Set;
> -import java.util.concurrent.Executors;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
>
>  import javax.servlet.ServletConfig;
> -import javax.servlet.ServletContext;
> +import javax.servlet.ServletException;
>  import javax.servlet.http.HttpServlet;
>  import javax.servlet.http.HttpServletRequest;
>  import javax.servlet.http.HttpServletResponse;
> @@ -52,63 +47,17 @@
>  * Servlet for rendering Gadgets, typically in an IFRAME.
>  */
>  public class GadgetRenderingServlet extends HttpServlet {
> -  private final GadgetServer gadgetServer;
> -  private final GadgetServerConfig serverConfig;
> -  private String jsServicePath;
> +  private CrossServletState servletState;
>   private static final String CAJA_PARAM = "caja";
>   private static final String USERPREF_PARAM_PREFIX = "up_";
>   private static final String LIBS_PARAM_NAME = "libs";
> -  private static final String JS_FILE_SUFFIX = ".js";
> -  public static final String DEFAULT_JS_SERVICE_PATH = "js/";
> +  private static final Logger logger
> +      = Logger.getLogger("org.apache.shindig.gadgets");
>
> -  /**
> -   * Creates a {@code GadgetRenderingServlet} with default executor,
> -   * caches, etc.
> -   *
> -   * Note that features aren't loaded until init() is called.
> -   *
> -   * @throws GadgetException If something went wrong during
> configuration.
> -   */
> -  public GadgetRenderingServlet() throws GadgetException {
> -    serverConfig = new GadgetServerConfig()
> -        .setExecutor(Executors.newCachedThreadPool())
> -        .setMessageBundleCache(new BasicGadgetDataCache<MessageBundle>())
> -        .setSpecCache(new BasicGadgetDataCache<GadgetSpec>())
> -        .setContentFetcher(new BasicRemoteContentFetcher(1024 * 1024))
> -        .setFeatureRegistry(new GadgetFeatureRegistry(null));
> -    gadgetServer = new GadgetServer(serverConfig);
> -  }
> -
> -  /**
> -   * Creates a servlet using a pre-configured server. Using this method
> -   * will cause init to ignore feature loading parameters.
> -   * @param server
> -   */
> -  public GadgetRenderingServlet(GadgetServer server) {
> -    gadgetServer = server;
> -    // Set this to null to indicate that all configuration has been done
> -    // custom.
> -    serverConfig = null;
> -  }
>
>   @Override
> -  public void init(ServletConfig config) {
> -    ServletContext context = config.getServletContext();
> -    String jsPath = context.getInitParameter("js-service-path");
> -    if (jsPath == null) {
> -      jsPath = DEFAULT_JS_SERVICE_PATH;
> -    }
> -    jsServicePath = jsPath;
> -    if (serverConfig != null) {
> -      // Using the default server.
> -      String features = context.getInitParameter("features");
> -      try {
> -        serverConfig.getFeatureRegistry().registerFeatures(features);
> -      } catch (GadgetException e) {
> -        e.printStackTrace();
> -        System.exit(1);
> -      }
> -    }
> +  public void init(ServletConfig config) throws ServletException {
> +    servletState = CrossServletState.get(config);
>   }
>
>   @Override
> @@ -153,11 +102,9 @@
>     String view = req.getParameter("view");
>     view = (view == null || view.length() == 0) ? GadgetSpec.DEFAULT_VIEW: view;
>     try {
> -      gadget = gadgetServer.processGadget(gadgetId,
> -                                          getPrefsFromRequest(req),
> -                                          context.getLocale(),
> -                                          RenderingContext.GADGET,
> -                                          options);
> +      gadget = servletState.getGadgetServer().processGadget(gadgetId,
> +          getPrefsFromRequest(req), context.getLocale(),
> +          RenderingContext.GADGET, options);
>       outputGadget(gadget, view, options, contentFilters, resp);
>     } catch (GadgetServer.GadgetProcessException e) {
>       outputErrors(e, resp);
> @@ -188,12 +135,6 @@
>     case URL:
>       outputUrlGadget(gadget, options, resp);
>       break;
> -    // default makes no sense here, as this is an enum, we want to insure
> that
> -    // we cover all cases of the enum, so leave it out.
> -//    default:
> -//      resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
> -//                     "Unexpected reror: unknown gadget type");
> -//      break;
>     }
>   }
>
> @@ -218,6 +159,7 @@
>
>     StringBuilder markup = new StringBuilder();
>     markup.append("<html><head>");
> +    // TODO: This is so wrong.
>     markup.append("<style type=\"text/css\">" +
>                   "body,td,div,span,p{font-family:arial,sans-serif;}" +
>                   "a {color:#0000cc;}a:visited {color:#551a8b;}" +
> @@ -228,6 +170,7 @@
>     StringBuilder externJs = new StringBuilder();
>     StringBuilder inlineJs = new StringBuilder();
>     String externFmt = "<script src=\"%s\"></script>\n";
> +    String forcedLibs = options.getForcedJsLibs();
>
>     for (JsLibrary library : gadget.getJsLibraries()) {
>       JsLibrary.Type type = library.getType();
> @@ -239,18 +182,17 @@
>         inlineJs.append(library.getContent()).append('\n');
>       } else {
>         // FILE or RESOURCE
> -        if (options.getForcedJsLibs() == null) {
> +        if (forcedLibs == null) {
>           inlineJs.append(library.getContent()).append('\n');
>         } // otherwise it was already included by options.forceJsLibs.
>       }
>     }
>
>     // Forced libs first.
> -    if (options.getForcedJsLibs() != null) {
> -      markup.append(String.format(externFmt,
> -                                  DEFAULT_JS_SERVICE_PATH +
> -                                  options.getForcedJsLibs() +
> -                                  JS_FILE_SUFFIX));
> +
> +    if (forcedLibs != null) {
> +      String[] libs = forcedLibs.split(":");
> +      markup.append(String.format(externFmt, servletState.getJsUrl
> (libs)));
>     }
>
>     if (inlineJs.length() > 0) {
> @@ -280,7 +222,7 @@
>         }
>       }
>     }
> -
> +
>     if (gadgetExceptions.size() > 0) {
>       throw new GadgetServer.GadgetProcessException(gadgetExceptions);
>     }
> @@ -294,28 +236,31 @@
>
>   private void outputUrlGadget(Gadget gadget,
>       ProcessingOptions options, HttpServletResponse resp) throws
> IOException {
> -    // UserPrefs portion of query string to tack on
>     // TODO: generalize this as injectedArgs on Gadget object
> +
> +    // Preserve existing query string parameters.
> +    URI redirURI = gadget.getContentHref();
> +    StringBuilder query = new StringBuilder(redirURI.getQuery());
> +
>     // TODO: userprefs on the fragment rather than query string
> -    String prefsQuery = getPrefsQueryString(gadget.getUserPrefValues());
> -    String libsQuery = null;
> +    query.append(getPrefsQueryString(gadget.getUserPrefValues()));
>
> -    if (options.getForcedJsLibs() == null) {
> -      libsQuery = getLibsQueryString(gadget.getRequires().keySet());
> +    String[] libs;
> +    String forcedLibs = options.getForcedJsLibs();
> +    if (forcedLibs == null) {
> +      libs = (String[])gadget.getRequires().keySet().toArray();
>     } else {
> -      libsQuery = DEFAULT_JS_SERVICE_PATH +
> -                  options.getForcedJsLibs() +
> -                  JS_FILE_SUFFIX;
> +      libs = forcedLibs.split(":");
>     }
> +    appendLibsToQuery(libs, query);
>
> -    URI redirURI = gadget.getContentHref();
>     try {
>       redirURI = new URI(redirURI.getScheme(),
>                          redirURI.getUserInfo(),
>                          redirURI.getHost(),
>                          redirURI.getPort(),
>                          redirURI.getPath(),
> -                         redirURI.getQuery() + prefsQuery + libsQuery,
> +                         query.toString(),
>                          redirURI.getFragment());
>     } catch (URISyntaxException e) {
>       // Not really ever going to happen; input values are already OK.
> @@ -337,6 +282,10 @@
>       markup.append(' ');
>       markup.append(error.getMessage());
>       markup.append('\n');
> +
> +      // Log the errors here for now. We might want different severity
> levels
> +      // for different error codes.
> +      logger.log(Level.INFO, "Failed to render gadget", error);
>     }
>     markup.append("</pre>");
>     markup.append("</body></html>");
> @@ -363,9 +312,9 @@
>       buf.append('&');
>       try {
>         buf.append(USERPREF_PARAM_PREFIX)
> -               .append(URLEncoder.encode(prefEntry.getKey(), "UTF8"))
> -               .append('=')
> -               .append(URLEncoder.encode(prefEntry.getValue(), "UTF8"));
> +           .append(URLEncoder.encode(prefEntry.getKey(), "UTF8"))
> +           .append("=")
> +           .append(URLEncoder.encode(prefEntry.getValue(), "UTF8"));
>       } catch (UnsupportedEncodingException e) {
>         // If UTF8 is somehow not supported, we may as well bail.
>         // Not a whole lot we can do without such support.
> @@ -375,26 +324,16 @@
>     return buf.toString();
>   }
>
> -  private String getLibsQueryString(Set<String> features) {
> -    StringBuilder buf = new StringBuilder();
> -    buf.append('&').append(LIBS_PARAM_NAME).append('=');
> -    buf.append(jsServicePath);
> -    if (features.size() == 0) {
> -      buf.append("core");
> -    } else {
> -      boolean first = true;
> -      for (String feature : features) {
> -        if (first) {
> -          first = false;
> -        } else {
> -          buf.append(':');
> -        }
> -        buf.append(feature);
> -      }
> -    }
> -    buf.append(JS_FILE_SUFFIX);
> -
> -    return buf.toString();
> +  /**
> +   * Appends libs to the query string.
> +   * @param libs
> +   * @param query
> +   */
> +  private void appendLibsToQuery(String[] libs, StringBuilder query) {
> +    query.append("&")
> +         .append(LIBS_PARAM_NAME)
> +         .append("=")
> +         .append(servletState.getJsUrl(libs));
>   }
>
>   /**
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java?rev=619684&r1=619683&r2=619684&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java
> Thu Feb  7 15:18:30 2008
> @@ -13,7 +13,6 @@
>  */
>  package org.apache.shindig.gadgets.http;
>
> -import org.apache.shindig.gadgets.GadgetException;
>  import org.apache.shindig.gadgets.GadgetFeatureFactory;
>  import org.apache.shindig.gadgets.GadgetFeatureRegistry;
>  import org.apache.shindig.gadgets.JsLibrary;
> @@ -26,7 +25,7 @@
>  import java.util.Set;
>
>  import javax.servlet.ServletConfig;
> -import javax.servlet.ServletContext;
> +import javax.servlet.ServletException;
>  import javax.servlet.http.HttpServlet;
>  import javax.servlet.http.HttpServletRequest;
>  import javax.servlet.http.HttpServletResponse;
> @@ -36,42 +35,24 @@
>  * Used by type=URL gadgets in loading JavaScript resources.
>  */
>  public class JsServlet extends HttpServlet {
> -  private GadgetFeatureRegistry registry = null;
> -
> -  /**
> -   * Create a JsServlet using a pre-configured feature registry.
> -   * @param registry
> -   */
> -  public JsServlet(GadgetFeatureRegistry registry) {
> -    this.registry = registry;
> -  }
> -
> -  /**
> -   * Creates a JsServlet without a default registry; the registry will be
> -   * created automatically when init is called.
> -   */
> -  public JsServlet() {
> -    registry = null;
> -  }
> +  private CrossServletState servletState;
> +  private static final long START_TIME = System.currentTimeMillis();
>
>   @Override
> -  public void init(ServletConfig config) {
> -    ServletContext context = config.getServletContext();
> -
> -    if (registry == null) {
> -      String features = context.getInitParameter("features");
> -      try {
> -        registry = new GadgetFeatureRegistry(features);
> -      } catch (GadgetException e) {
> -        e.printStackTrace();
> -        throw new RuntimeException(e);
> -      }
> -    }
> +  public void init(ServletConfig config) throws ServletException {
> +    servletState = CrossServletState.get(config);
>   }
>
>   @Override
>   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
>       throws IOException {
> +    // If an If-Modified-Since header is ever provided, we always say
> +    // not modified. This is because when there actually is a change,
> +    // cache busting should occur.
> +    if (req.getHeader("If-Modified-Since") != null) {
> +      resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
> +      return;
> +    }
>     // Use the last component as filename; prefix is ignored
>     String uri = req.getRequestURI();
>     // We only want the file name part. There will always be at least 1
> slash
> @@ -94,6 +75,8 @@
>         = new HashSet<GadgetFeatureRegistry.Entry>();
>     Set<String> missing = new HashSet<String>();
>
> +    GadgetFeatureRegistry registry
> +        = servletState.getGadgetServer
> ().getConfig().getFeatureRegistry();
>     if (registry.getIncludedFeatures(needed, found, missing)) {
>       String containerParam = req.getParameter("c");
>       RenderingContext context;
> @@ -105,6 +88,8 @@
>
>       Set<GadgetFeatureRegistry.Entry> done
>           = new HashSet<GadgetFeatureRegistry.Entry>();
> +
> +      // TODO: This doesn't work correctly under JDK 1.5, but it does
> under 1.6
>       do {
>         for (GadgetFeatureRegistry.Entry entry : found) {
>           if (!done.contains(entry) &&
> @@ -145,8 +130,15 @@
>    * @param response The HTTP response
>    */
>   private void setCachingHeaders(HttpServletResponse response) {
> -    response.setHeader("Cache-Control", "public,max-age=2592000");
> -    response.setDateHeader("Expires", System.currentTimeMillis()
> -                                     + 2592000000L);
> +
> +    // Most browsers accept this. 2030 is the last round year before
> +    // the end of time.
> +    response.setHeader("Expires", "Tue, 01 Jan 2030 00:00:01 GMT");
> +
> +    // IE seems to need this (10 years should be enough).
> +    response.setHeader("Cache-Control", "public,max-age=315360000");
> +
> +    // Firefox requires this for certain cases.
> +    response.setDateHeader("Last-Modified", START_TIME);
>   }
>  }
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java?rev=619684&r1=619683&r2=619684&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
> Thu Feb  7 15:18:30 2008
> @@ -18,7 +18,6 @@
>  */
>  package org.apache.shindig.gadgets.http;
>
> -import org.apache.shindig.gadgets.BasicRemoteContentFetcher;
>  import org.apache.shindig.gadgets.GadgetException;
>  import org.apache.shindig.gadgets.GadgetSigner;
>  import org.apache.shindig.gadgets.GadgetToken;
> @@ -48,13 +47,9 @@
>   private static final int TWO_HOURS_IN_MS = 7200000;
>   private static final int ONE_HOUR_IN_SECS = 3600;
>   private static final int MAX_PROXY_SIZE = 1024 * 1024;
> -
> +
>   private final RemoteContentFetcher fetcher;
>
> -  public ProxyHandler() {
> -    this(new BasicRemoteContentFetcher(MAX_PROXY_SIZE));
> -  }
> -
>   public ProxyHandler(RemoteContentFetcher fetcher) {
>     this.fetcher = fetcher;
>   }
> @@ -203,7 +198,9 @@
>   private GadgetToken extractAndValidateToken(HttpServletRequest request,
>       GadgetSigner signer) throws ServletException {
>     try {
> -      if (signer == null) return null;
> +      if (signer == null) {
> +        return null;
> +      }
>       String token = request.getParameter("st");
>       if (token == null) {
>         token = "";
> @@ -229,7 +226,7 @@
>
>   /**
>    * Sign a URL with a GadgetToken if needed
> -   * @return
> +   * @return
>    */
>   private URL signUrl(URL originalUrl, GadgetToken token,
>       HttpServletRequest request) throws ServletException {
> @@ -238,7 +235,7 @@
>           !"signed".equals(request.getParameter("authz"))) {
>         return originalUrl;
>       }
> -      return token.signUrl(originalUrl, "GET", // TODO: request.getMethod
> ()
> +      return token.signUrl(originalUrl, "GET", // TODO: request.getMethod
> ()
>           request.getParameterMap());
>     } catch (GadgetException ge) {
>       throw new ServletException(ge);
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java?rev=619684&r1=619683&r2=619684&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
> Thu Feb  7 15:18:30 2008
> @@ -18,28 +18,38 @@
>  */
>  package org.apache.shindig.gadgets.http;
>
> -import org.apache.shindig.gadgets.BasicGadgetSigner;
> -import org.apache.shindig.gadgets.GadgetSigner;
> +import org.apache.shindig.gadgets.GadgetServerConfigReader;
>
>  import java.io.IOException;
>
> +import javax.servlet.ServletConfig;
>  import javax.servlet.ServletException;
>  import javax.servlet.http.HttpServlet;
>  import javax.servlet.http.HttpServletRequest;
>  import javax.servlet.http.HttpServletResponse;
>
>  public class ProxyServlet extends HttpServlet {
> -  private final GadgetSigner signer;
> -  private final ProxyHandler handler;
> +  private CrossServletState servletState;
> +  private ProxyHandler proxyHandler;
> +
> +  @Override
> +  public void init(ServletConfig config) throws ServletException {
> +    servletState = CrossServletState.get(config);
> +    GadgetServerConfigReader serverConfig
> +        = servletState.getGadgetServer().getConfig();
> +    proxyHandler = new ProxyHandler(serverConfig.getContentFetcher());
> +  }
>
>   @Override
>   protected void doGet(HttpServletRequest request, HttpServletResponse
> response)
>       throws ServletException, IOException {
>     String output = request.getParameter("output");
>     if ("js".equals(output)) {
> -      handler.fetchJson(request, response, signer);
> +      proxyHandler.fetchJson(
> +          request, response, servletState.getGadgetSigner(request));
>     } else {
> -      handler.fetch(request, response, signer);
> +      proxyHandler.fetch(
> +          request, response, servletState.getGadgetSigner(request));
>     }
>   }
>
> @@ -48,22 +58,5 @@
>       throws ServletException, IOException {
>     // Currently they are identical
>     doGet(request, response);
> -  }
> -
> -  /**
> -   * Constructs a ProxyServlet with the default (non-secure)
> GadgetSigner.
> -   */
> -  public ProxyServlet() {
> -    this(new BasicGadgetSigner(), new ProxyHandler());
> -  }
> -
> -  /**
> -   * Creates a ProxyServlet using the specified GadgetSigner.
> -   * @param signer Used to sign and verify requests
> -   * @param handler Used to fetch proxied content
> -   */
> -  public ProxyServlet(GadgetSigner signer, ProxyHandler handler) {
> -    this.signer = signer;
> -    this.handler = handler;
>   }
>  }
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java?rev=619684&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java
> Thu Feb  7 15:18:30 2008
> @@ -0,0 +1,48 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.shindig.gadgets.http;
> +
> +import java.io.IOException;
> +
> +import javax.servlet.ServletConfig;
> +import javax.servlet.ServletException;
> +import javax.servlet.http.HttpServlet;
> +import javax.servlet.http.HttpServletRequest;
> +import javax.servlet.http.HttpServletResponse;
> +
> +/**
> + * Handles RPC metadata requests.
> + */
> +public class RpcServlet extends HttpServlet {
> +  private CrossServletState state;
> +
> +  @Override
> +  protected void doGet(HttpServletRequest request, HttpServletResponse
> response)
> +      throws ServletException, IOException {
> +  }
> +
> +  @Override
> +  public void init(ServletConfig config) throws ServletException {
> +    state = CrossServletState.get(config);
> +  }
> +
> +  public RpcServlet() {
> +  }
> +}
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml?rev=619684&r1=619683&r2=619684&view=diff
>
> ==============================================================================
> --- incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml
> (original)
> +++ incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml
> Thu Feb  7 15:18:30 2008
> @@ -19,48 +19,63 @@
>         "http://java.sun.com/dtd/web-app_2_3.dtd">
>
>  <web-app>
> -    <!-- configuration -->
> -    <context-param>
> -        <param-name>features</param-name>
> -        <param-value>res://features/features.txt</param-value>
> -    </context-param>
> -
> -    <!-- Render a Gadget -->
> -    <servlet>
> -        <servlet-name>xml-to-html</servlet-name>
> -        <servlet-class>
> -            org.apache.shindig.gadgets.http.GadgetRenderingServlet
> -        </servlet-class>
> -    </servlet>
> -
> -    <!-- Proxy -->
> -    <servlet>
> -        <servlet-name>proxy</servlet-name>
> -        <servlet-class>
> -            org.apache.shindig.gadgets.http.ProxyServlet
> -        </servlet-class>
> -    </servlet>
> -
> -
> -    <!-- javascript serving -->
> -    <servlet>
> -        <servlet-name>js</servlet-name>
> -        <servlet-class>org.apache.shindig.gadgets.http.JsServlet
> </servlet-class>
> -    </servlet>
> -
> -    <servlet-mapping>
> -        <servlet-name>js</servlet-name>
> -        <url-pattern>/js/*</url-pattern>
> -    </servlet-mapping>
> -
> -    <servlet-mapping>
> -        <servlet-name>proxy</servlet-name>
> -        <url-pattern>/proxy</url-pattern>
> -    </servlet-mapping>
> -
> -    <servlet-mapping>
> -        <servlet-name>xml-to-html</servlet-name>
> -        <url-pattern>/ifr</url-pattern>
> -    </servlet-mapping>
> -
> +  <!-- configuration -->
> +  <context-param>
> +    <param-name>features</param-name>
> +    <param-value>res://features/features.txt</param-value>
> +  </context-param>
> +  <context-param>
> +    <param-name>servlet-data-class</param-name>
> +    <param-value>org.apache.shindig.gadgets.http.DefaultCrossServletState
> </param-value>
> +  </context-param>
> +
> +  <!-- Render a Gadget -->
> +  <servlet>
> +    <servlet-name>xml-to-html</servlet-name>
> +    <servlet-class>
> +      org.apache.shindig.gadgets.http.GadgetRenderingServlet
> +    </servlet-class>
> +  </servlet>
> +
> +  <!-- Proxy -->
> +  <servlet>
> +    <servlet-name>proxy</servlet-name>
> +    <servlet-class>
> +      org.apache.shindig.gadgets.http.ProxyServlet
> +    </servlet-class>
> +  </servlet>
> +
> +  <!-- Metadata RPC -->
> +  <servlet>
> +    <servlet-name>rpc</servlet-name>
> +    <servlet-class>
> +      org.apache.shindig.gadgets.http.RpcServlet
> +    </servlet-class>
> +  </servlet>
> +
> +  <!-- javascript serving -->
> +  <servlet>
> +    <servlet-name>js</servlet-name>
> +    <servlet-class>org.apache.shindig.gadgets.http.JsServlet
> </servlet-class>
> +  </servlet>
> +
> +  <servlet-mapping>
> +    <servlet-name>js</servlet-name>
> +    <url-pattern>/js/*</url-pattern>
> +  </servlet-mapping>
> +
> +  <servlet-mapping>
> +    <servlet-name>proxy</servlet-name>
> +    <url-pattern>/proxy</url-pattern>
> +  </servlet-mapping>
> +
> +  <servlet-mapping>
> +    <servlet-name>xml-to-html</servlet-name>
> +    <url-pattern>/ifr</url-pattern>
> +  </servlet-mapping>
> +
> +  <servlet-mapping>
> +    <servlet-name>rpc</servlet-name>
> +    <url-pattern>/rpc</url-pattern>
> +  </servlet-mapping>
>  </web-app>
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java?rev=619684&r1=619683&r2=619684&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
> Thu Feb  7 15:18:30 2008
> @@ -27,29 +27,48 @@
>  import static org.easymock.EasyMock.expect;
>  import static org.easymock.EasyMock.isA;
>
> -import java.util.concurrent.Executor;
>  import java.util.concurrent.Executors;
>
>  public class GadgetServerTest extends EasyMockTestCase {
> -  final Executor executor = Executors.newCachedThreadPool();
> -  final GadgetServer gadgetServer;
> +  GadgetServer gadgetServer;
>   final RemoteContentFetcher fetcher = mock(RemoteContentFetcher.class);
>   @SuppressWarnings(value="unchecked")
>   final GadgetDataCache<GadgetSpec> specCache = mock(GadgetDataCache.class
> );
>   @SuppressWarnings(value="unchecked")
>   final GadgetDataCache<MessageBundle> bundleCache = mock(
> GadgetDataCache.class);
>
> -  public GadgetServerTest() throws GadgetException {
> -    // TODO: need to test for configuration errors.
> -    gadgetServer = new GadgetServer(new GadgetServerConfig()
> -        .setExecutor(executor)
> -        .setSpecCache(specCache)
> -        .setMessageBundleCache(bundleCache)
> -        .setFeatureRegistry(new GadgetFeatureRegistry(null))
> -        .setContentFetcher(fetcher));
> +  void initServer(GadgetServerConfigReader customConfig) throws
> GadgetException {
> +    GadgetServerConfig config = new GadgetServerConfig();
> +
> +    if (customConfig != null) {
> +      config.copyFrom(customConfig);
> +    }
> +
> +    if (config.getExecutor() == null) {
> +      config.setExecutor(Executors.newCachedThreadPool());
> +    }
> +
> +    if (config.getSpecCache() == null) {
> +      config.setSpecCache(specCache);
> +    }
> +
> +    if (config.getMessageBundleCache() == null) {
> +      config.setMessageBundleCache(bundleCache);
> +    }
> +
> +    if (config.getFeatureRegistry() == null) {
> +      config.setFeatureRegistry(new GadgetFeatureRegistry(null));
> +    }
> +
> +    if (config.getContentFetcher() == null) {
> +      config.setContentFetcher(fetcher);
> +    }
> +
> +    gadgetServer = new GadgetServer(config);
>   }
>
>   public void testGadgetSpecNotInCache() throws Exception {
> +    initServer(null);
>     RemoteContent results = new RemoteContent(200,
> DATETIME_XML.getBytes(), null);
>     ProcessingOptions options = new ProcessingOptions();
>
> @@ -65,6 +84,7 @@
>   }
>
>   public void testGadgetSpecInCache() throws Exception {
> +    initServer(null);
>     expect(specCache.get
> (eq(DATETIME_URI_STRING))).andReturn(DATETIME_SPEC);
>     replay();
>
> @@ -75,6 +95,7 @@
>   }
>
>   public void testBasicGadget() throws Exception {
> +    initServer(null);
>     RemoteContent results = new RemoteContent(200,
> DATETIME_XML.getBytes(), null);
>     ProcessingOptions options = new ProcessingOptions();
>
> @@ -93,8 +114,7 @@
>
>   public void testBlacklistedGadget() throws Exception {
>     GadgetBlacklist blacklist = mock(GadgetBlacklist.class);
> -    gadgetServer.setGadgetBlacklist(blacklist);
> -
> +    initServer(new GadgetServerConfig().setGadgetBlacklist(blacklist));
>     expect(specCache.get(eq(DATETIME_URI_STRING))).andReturn(null);
>     expect(blacklist.isBlacklisted(eq(DATETIME_URI))).andReturn(true);
>     replay();
>
>
>

Re: svn commit: r619684 - in /incubator/shindig/trunk: features/core/ java/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ java/gadgets/src/main/webapp/WEB-INF/ java/gadgets/

Posted by Kevin Brown <et...@google.com>.
On Feb 7, 2008 5:33 PM, Cassie <do...@apache.org> wrote:

> Just a quick thought - did you test the samplecontainer? It seems like
> moving things into /files might affect it.
> Thanks.
>
> - Cassie


Yes, we have to update a couple of those files as well to make sure it's
consistent across the board. I'll go through all the files and submit
changes tonight if nobody beats me to it.


>
>
> On Thu, Feb 7, 2008 at 3:18 PM, <et...@apache.org> wrote:
>
> > Author: etnu
> > Date: Thu Feb  7 15:18:30 2008
> > New Revision: 619684
> >
> > URL: http://svn.apache.org/viewvc?rev=619684&view=rev
> > Log:
> > - Merged in changes from SHINDIG-51 and prepared code for merging
> > SHINDIG-35
> > - Fixed caching behavior in JsServlet; files will now be cached
> > indefinitely and a cache busting token must be appended to get the new
> > version.
> > - Added placeholder for RpcServlet for SHINDIG-25.
> > - Fixed static files path in pom.xml to be compatible with the jar-based
> > build (no longer places all files into the root; now files are in
> > /gadgets/files/). This may
> >  require updating some of the static files, but currently examples all
> > seem to work.
> > - Cleaned up a spec deviation in gadgets.io (did not properly handle
> > POST_DATA) and collapsed "enums" to their simplest form.
> >
> >
> > Added:
> >
> >
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
> >
> >
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
> >
> >
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java
> > Modified:
> >    incubator/shindig/trunk/features/core/io.js
> >    incubator/shindig/trunk/java/gadgets/pom.xml
> >
> >
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java
> >
> >
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
> >
> >
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java
> >
> >
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java
> >
> >
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
> >
> >
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
> >    incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml
> >
> >
>  incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
> >
> > Modified: incubator/shindig/trunk/features/core/io.js
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/io.js?rev=619684&r1=619683&r2=619684&view=diff
> >
> >
> ==============================================================================
> > --- incubator/shindig/trunk/features/core/io.js (original)
> > +++ incubator/shindig/trunk/features/core/io.js Thu Feb  7 15:18:30 2008
> > @@ -82,37 +82,37 @@
> >       case "FEED":
> >         resp.data = gadgets.json.parse(resp.text);
> >         if (!resp.data) {
> > -          resp.errors = ["failed to parse JSON"];
> > +          resp.errors.push("failed to parse JSON");
> >           resp.data = null;
> >         }
> >         break;
> > -     case "DOM":
> > -      var dom;
> > -      if (window.ActiveXObject) {
> > -        dom = new ActiveXObject("Microsoft.XMLDOM");
> > -        dom.async = false;
> > -        dom.validateOnParse = false;
> > -        dom.resolveExternals = false;
> > -        if (!dom.loadXML(resp.text)) {
> > -          resp.errors = ["failed to parse XML"];
> > +      case "DOM":
> > +        var dom;
> > +        if (window.ActiveXObject) {
> > +          dom = new ActiveXObject("Microsoft.XMLDOM");
> > +          dom.async = false;
> > +          dom.validateOnParse = false;
> > +          dom.resolveExternals = false;
> > +          if (!dom.loadXML(resp.text)) {
> > +            resp.errors.push("failed to parse XML");
> > +          } else {
> > +            resp.data = dom;
> > +          }
> >         } else {
> > -          resp.data = dom;
> > +          var parser = new DOMParser();
> > +          dom = parser.parseFromString(resp.text, "text/xml");
> > +          if ("parsererror" == dom.documentElement.nodeName) {
> > +            resp.errors.push("failed to parse XML");
> > +          } else {
> > +            resp.data = dom;
> > +          }
> >         }
> > -      } else {
> > -        var parser = new DOMParser();
> > -        dom = parser.parseFromString(resp.text, "text/xml");
> > -        if ("parsererror" == dom.documentElement.nodeName) {
> > -          resp.errors = ["failed to parse XML"];
> > -        } else {
> > -          resp.data = dom;
> > -        }
> > -      }
> > -      break;
> > -    default:
> > -      resp.data = resp.text;
> > -      break;
> > -   }
> > -   callback(resp);
> > +        break;
> > +      default:
> > +        resp.data = resp.text;
> > +        break;
> > +    }
> > +    callback(resp);
> >   }
> >
> >   return /** @scope gadgets.io */ {
> > @@ -145,10 +145,8 @@
> >           encodeURIComponent(url));
> >
> >       // Check if authorization is requested
> > -      if (opt_params && opt_params.AUTHORIZATION &&
> > -          gadgets.io.AuthorizationType
> > [opt_params.AUTHORIZATION.toUpperCase()]
> > -              != gadgets.io.AuthorizationType.NONE) {
> > -        newUrl += "&authz=" + opt_params.AUTHORIZATION.toLowerCase();
> > +      if (params.AUTHORIZATION && params.AUTHORIZATION !== "NONE") {
> > +        newUrl += "&authz=" + params.AUTHORIZATION.toLowerCase();
> >         // Add the security-token if available
> >         if (gadgets.util.getUrlParameters()["st"]) {
> >           newUrl += "&st=" + gadgets.util.getUrlParameters()["st"];
> > @@ -160,10 +158,11 @@
> >         xhr.onreadystatechange = gadgets.util.makeClosure(null,
> >             processResponse, url, callback, params, xhr);
> >       }
> > -      if (params.METHOD == "POST") {
> > -        xhr.setRequestHeader('Content-Type',
> > 'application/x-www-form-urlencoded');
> > -        if (params.postData) {
> > -          xhr.send("postData=" + encodeURIComponent(params.postData));
> > +      if (params.METHOD === "POST") {
> > +        xhr.setRequestHeader('Content-Type',
> > +            'application/x-www-form-urlencoded');
> > +        if (params.POST_DATA) {
> > +          xhr.send("postData=" + encodeURIComponent(params.POST_DATA));
> >         } else {
> >           xhr.send("postData=");
> >         }
> > @@ -225,189 +224,25 @@
> >   };
> >  }();
> >
> > -// TODO: This can all be removed after the spec is published. This is
> > only
> > -// here to satisfy documentation requirements.
> > -
> > -/**
> > - * @static
> > - * @class
> > - * Used by the
> > - * <a href="gadgets.io.html#makeRequest">
> > - * <code>gadgets.io.makeRequest()</code></a> method.
> > - * @name gadgets.io.RequestParameters
> > - */
> > -gadgets.io.RequestParameters = {
> > -  /**
> > -   * The method to use when fetching content from the URL;
> > -   * defaults to <code>MethodType.GET</a></code>.
> > -   * Specified as a
> > -   * <a href="gadgets.io.MethodType.html">MethodType</a>.
> > -   *
> > -   * @member gadgets.io.RequestParameters
> > -   */
> > -   METHOD : 'METHOD',
> > -
> > -  /**
> > -   * The type of content that lives at the URL;
> > -   * defaults to <code>ContentType.HTML</code>.
> > -   * Specified as a
> > -   * <a href="gadgets.io.ContentType.html">
> > -   * ContentType</a>.
> > -   *
> > -   * @member gadgets.io.RequestParameters
> > -   */
> > -  CONTENT_TYPE : "CONTENT_TYPE",
> > -
> > -  /**
> > -   * The data to send to the URL using the POST method;
> > -   * defaults to null.
> > -   * Specified as a <code>String</code>.
> > -   *
> > -   * @member gadgets.io.RequestParameters
> > -   */
> > -  POST_DATA : "POST_DATA",
> > -
> > -  /**
> > -   * The HTTP headers to send to the URL;
> > -   * defaults to null.
> > -   * Specified as a <code>Map.&lt;String,String&gt;</code>.
> > -   *
> > -   * @member gadgets.io.RequestParameters
> > -   */
> > -  HEADERS : "HEADERS",
> > -
> > -  /**
> > -   * The type of authentication to use when fetching the content;
> > -   * defaults to <code>AuthorizationType.NONE</code>.
> > -   * Specified as an
> > -   * <a href="gadgets.io.AuthorizationType.html">
> > -   * AuthorizationType</a>.
> > -   *
> > -   * @member gadgets.io.RequestParameters
> > -   */
> > -  AUTHORIZATION : 'AUTHORIZATION',
> > -
> > -
> > -  /**
> > -   * If the content is a feed, the number of entries to fetch;
> > -   * defaults to 3.
> > -   * Specified as a <code>Number</code>.
> > -   *
> > -   * @member gadgets.io.RequestParameters
> > -   */
> > -  NUM_ENTRIES : 'NUM_ENTRIES',
> > -
> > -  /**
> > -   * If the content is a feed, whether to fetch summaries for that
> feed;
> > -   * defaults to false.
> > -   * Specified as a <code>Boolean</code>.
> > -   *
> > -   * @member gadgets.io.RequestParameters
> > -   */
> > -  GET_SUMMARIES : 'GET_SUMMARIES'
> > -};
> > -
> > -
> > -/**
> > - * @static
> > - * @class
> > - * Used by
> > - * <a href="gadgets.io.RequestParameters.html">
> > - * RequestParameters</a>.
> > - * @name gadgets.io.MethodType
> > - */
> > -gadgets.io.MethodType = {
> > -  /**
> > -   * The default type.
> > -   * @member gadgets.io.MethodType
> > -   */
> > -  GET : 'GET',
> > -
> > -  /**
> > -   * Not supported by all containers.
> > -   * @member gadgets.io.MethodType
> > -   */
> > -  POST : 'POST',
> > -
> > -  /**
> > -   * Not supported by all containers.
> > -   * @member gadgets.io.MethodType
> > -   */
> > -  PUT : 'PUT',
> > -
> > -  /**
> > -   * Not supported by all containers.
> > -   * @member gadgets.io.MethodType
> > -   */
> > -  DELETE : 'DELETE',
> > -
> > -  /**
> > -   * Not supported by all containers.
> > -   * @member gadgets.io.MethodType
> > -   */
> > -  HEAD : 'HEAD'
> > -};
> > -
> > -
> > -/**
> > - * @static
> > - * @class
> > - * Used by
> > - * <a href="gadgets.io.RequestParameters.html">
> > - * RequestParameters</a>.
> > - * @name gadgets.io.ContentType
> > - */
> > -gadgets.io.ContentType = {
> > -  /**
> > -   * Returns text; used for fetching HTML.
> > -   * @member gadgets.io.ContentType
> > -   */
> > -  TEXT : 'TEXT',
> > -
> > -  /**
> > -   * Returns a DOM object; used for fetching XML.
> > -   * @member gadgets.io.ContentType
> > -   */
> > -  DOM : 'DOM',
> > -
> > -  /**
> > -   * Returns a JSON object.
> > -   * @member gadgets.io.ContentType
> > -   */
> > -  JSON : 'JSON',
> > -
> > -  /**
> > -   * Returns a JSON representation of a feed.
> > -   * @member gadgets.io.ContentType
> > -   */
> > -  FEED : 'FEED'
> > -};
> > -
> > -
> > -/**
> > - * @static
> > - * @class
> > - * Used by
> > - * <a href="gadgets.io.RequestParameters.html">
> > - * RequestParameters</a>.
> > - * @name gadgets.io.AuthorizationType
> > - */
> > -gadgets.io.AuthorizationType = {
> > -  /**
> > -   * No authorization.
> > -   * @member gadgets.io.AuthorizationType
> > -   */
> > -  NONE : 'NONE',
> > -
> > -  /**
> > -   * The request will be signed by the container.
> > -   * @member gadgets.io.AuthorizationType
> > -   */
> > -  SIGNED : 'SIGNED',
> > -
> > -  /**
> > -   * The container will use full authentication.
> > -   * @member gadgets.io.AuthorizationType
> > -   */
> > -  AUTHENTICATED : 'AUTHENTICATED'
> > -};
> > +gadgets.io.RequestParameters = gadgets.util.makeEnum([
> > +  "METHOD",
> > +  "CONTENT_TYPE",
> > +  "POST_DATA",
> > +  "HEADERS",
> > +  "AUTHORIZATION",
> > +  "NUM_ENTRIES",
> > +  "GET_SUMMARIES"
> > +]);
> > +
> > +// PUT, DELETE, and HEAD not supported currently.
> > +gadgets.io.MethodType = gadgets.util.makeEnum([
> > +  "GET", "POST", "PUT", "DELETE", "HEAD"
> > +]);
> > +
> > +gadgets.io.ContentType = gadgets.util.makeEnum([
> > +  "TEXT", "DOM", "JSON", "FEED"
> > +]);
> > +
> > +gadgets.io.AuthorizationType = gadgets.util.makeEnum([
> > +  "NONE", "SIGNED", "AUTHENTICATED"
> > +]);
> > \ No newline at end of file
> >
> > Modified: incubator/shindig/trunk/java/gadgets/pom.xml
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/pom.xml?rev=619684&r1=619683&r2=619684&view=diff
> >
> >
> ==============================================================================
> > --- incubator/shindig/trunk/java/gadgets/pom.xml (original)
> > +++ incubator/shindig/trunk/java/gadgets/pom.xml Thu Feb  7 15:18:30
> 2008
> > @@ -28,6 +28,7 @@
> >             <resource>
> >               <!-- this is relative to the pom.xml directory -->
> >               <directory>../../javascript/</directory>
> > +              <targetPath>files</targetPath>
> >               <includes>
> >                 <include>**/*.*</include>
> >               </includes>
> >
> > Modified:
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java?rev=619684&r1=619683&r2=619684&view=diff
> >
> >
> ==============================================================================
> > ---
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java
> > (original)
> > +++
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java
> > Thu Feb  7 15:18:30 2008
> > @@ -146,6 +146,13 @@
> >   }
> >
> >   /**
> > +   * @return All registered features.
> > +   */
> > +  public Map<String, Entry> getAllFeatures() {
> > +    return Collections.unmodifiableMap(features);
> > +  }
> > +
> > +  /**
> >    * Attempts to retrieve all the {@code GadgetFeature} classes
> specified
> >    * in the {@code needed} list. Those that are found are returned in
> >    * {@code resultsFound}, while the names of those that are missing are
> >
> > Modified:
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java?rev=619684&r1=619683&r2=619684&view=diff
> >
> >
> ==============================================================================
> > ---
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
> > (original)
> > +++
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
> > Thu Feb  7 15:18:30 2008
> > @@ -22,39 +22,21 @@
> >  import java.net.MalformedURLException;
> >  import java.util.ArrayList;
> >  import java.util.Arrays;
> > +import java.util.Collections;
> >  import java.util.HashSet;
> >  import java.util.LinkedList;
> >  import java.util.List;
> >  import java.util.Locale;
> >  import java.util.Map;
> >  import java.util.Set;
> > -import java.util.Collections;
> >  import java.util.concurrent.Callable;
> >  import java.util.concurrent.CompletionService;
> >  import java.util.concurrent.ExecutionException;
> > -import java.util.concurrent.Executor;
> >  import java.util.concurrent.ExecutorCompletionService;
> >  import java.util.concurrent.Future;
> > -import java.util.logging.Logger;
> > -import java.util.logging.Level;
> >
> >  public class GadgetServer {
> > -  private final GadgetServerConfig config;
> > -
> > -  private static final Logger logger
> > -      = Logger.getLogger("org.apache.shindig.gadgets");
> > -
> > -  /**
> > -   * Creates a GadgetServer without a config.
> > -   *
> > -   * @deprecated Replaced by {@link
> > #GadgetServer(GadgetServerConfigReader)}.
> > -   * @param executor
> > -   */
> > -  @Deprecated
> > -  public GadgetServer(Executor executor) {
> > -    config = new GadgetServerConfig();
> > -    config.setExecutor(executor);
> > -  }
> > +  private final GadgetServerConfigReader config;
> >
> >   /**
> >    * Creates a GadgetServer using the provided configuration.
> > @@ -72,51 +54,11 @@
> >     Check.notNull(configuration.getContentFetcher(),
> >         "ContentFetcher is required.");
> >
> > -    config = new GadgetServerConfig();
> > +    config = new GadgetServerConfigReader();
> >     config.copyFrom(configuration);
> >   }
> >
> >   /**
> > -   * @deprecated Replaced by {@link
> > #GadgetServer(GadgetServerConfigReader)}.
> > -   */
> > -  @Deprecated
> > -  public void setSpecCache(GadgetDataCache<GadgetSpec> specCache) {
> > -    config.setSpecCache(specCache);
> > -  }
> > -
> > -  /**
> > -   * @deprecated Replaced by {@link
> > #GadgetServer(GadgetServerConfigReader)}.
> > -   */
> > -  @Deprecated
> > -  public void setMessageBundleCache(GadgetDataCache<MessageBundle>
> cache)
> > {
> > -    config.setMessageBundleCache(cache);
> > -  }
> > -
> > -  /**
> > -   * @deprecated Replaced by {@link
> > #GadgetServer(GadgetServerConfigReader)}.
> > -   */
> > -  @Deprecated
> > -  public void setContentFetcher(RemoteContentFetcher fetcher) {
> > -    config.setContentFetcher(fetcher);
> > -  }
> > -
> > -  /**
> > -   * @deprecated Replaced by {@link
> > #GadgetServer(GadgetServerConfigReader)}.
> > -   */
> > -  @Deprecated
> > -  public void setGadgetFeatureRegistry(GadgetFeatureRegistry registry)
> {
> > -    config.setFeatureRegistry(registry);
> > -  }
> > -
> > -  /**
> > -   * @deprecated Replaced by {@link
> > #GadgetServer(GadgetServerConfigReader)}.
> > -   */
> > -  @Deprecated
> > -  public void setGadgetBlacklist(GadgetBlacklist gadgetBlacklist) {
> > -    config.setGadgetBlacklist(gadgetBlacklist);
> > -  }
> > -
> > -  /**
> >    * @return A read-only view of the server's configuration.
> >    */
> >   public GadgetServerConfigReader getConfig() {
> > @@ -140,22 +82,6 @@
> >                               RenderingContext rctx,
> >                               ProcessingOptions options)
> >       throws GadgetProcessException {
> > -    // TODO: Remove dep checks when GadgetServer(Executor) is removed.
> > -    if (config.getSpecCache() == null) {
> > -      throw new GadgetProcessException(
> > GadgetException.Code.MISSING_SPEC_CACHE);
> > -    }
> > -    if (config.getMessageBundleCache() == null ) {
> > -      throw new GadgetProcessException(
> > -          GadgetException.Code.MISSING_MESSAGE_BUNDLE_CACHE);
> > -    }
> > -    if (config.getContentFetcher() == null) {
> > -      throw new GadgetProcessException(
> > -          GadgetException.Code.MISSING_REMOTE_OBJECT_FETCHER);
> > -    }
> > -    if (config.getFeatureRegistry() == null) {
> > -      throw new GadgetProcessException(
> > -          GadgetException.Code.MISSING_FEATURE_REGISTRY);
> > -    }
> >
> >     // Queue/tree of all jobs to be run for successful processing
> >     GadgetContext gc = new GadgetContext(config.getContentFetcher(),
> > @@ -242,8 +168,6 @@
> >       }
> >
> >       if (gadgetException != null) {
> > -        logger.log(Level.SEVERE, gadgetException.getCode().toString(),
> > gadgetException);
> > -
> >         // Add to list of all exceptions caught, clear jobs, and
> continue
> >         // to aggressively catch as many exceptions as possible. Since
> >         // tasks are running anyway, we may as well get their results in
> > @@ -320,7 +244,8 @@
> >
> >     private WorkflowContext(GadgetContext context) {
> >       this.context = context;
> > -      this.depsDone = Collections.synchronizedSet(new
> > HashSet<WorkflowDependency>());
> > +      this.depsDone
> > +          = Collections.synchronizedSet(new
> > HashSet<WorkflowDependency>());
> >       this.jobsToRun = new WorkflowJobList(this);
> >     }
> >   }
> > @@ -431,8 +356,9 @@
> >       Map<String, GadgetSpec.FeatureSpec> requires =
> wc.gadget.getRequires
> > ();
> >       Set<String> needed = new HashSet<String>(requires.size());
> >       Set<String> optionalNames = new HashSet<String>();
> > -
> > -      for (Map.Entry<String, GadgetSpec.FeatureSpec> entry :
> > requires.entrySet()) {
> > +
> > +      for (Map.Entry<String, GadgetSpec.FeatureSpec> entry :
> > +        requires.entrySet()) {
> >         needed.add(entry.getKey());
> >         if (entry.getValue().isOptional()) {
> >           optionalNames.add(entry.getKey());
> >
> > Added:
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java?rev=619684&view=auto
> >
> >
> ==============================================================================
> > ---
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
> > (added)
> > +++
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
> > Thu Feb  7 15:18:30 2008
> > @@ -0,0 +1,107 @@
> > +/*
> > + * Licensed to the Apache Software Foundation (ASF) under one
> > + * or more contributor license agreements.  See the NOTICE file
> > + * distributed with this work for additional information
> > + * regarding copyright ownership.  The ASF licenses this file
> > + * to you 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.shindig.gadgets.http;
> > +
> > +import org.apache.shindig.gadgets.Gadget;
> > +import org.apache.shindig.gadgets.GadgetServer;
> > +import org.apache.shindig.gadgets.GadgetSigner;
> > +
> > +import java.util.logging.Logger;
> > +
> > +import javax.servlet.ServletConfig;
> > +import javax.servlet.ServletContext;
> > +import javax.servlet.ServletException;
> > +import javax.servlet.http.HttpServletRequest;
> > +
> > +/**
> > + * Loads shared configuration and creates appropriate class instances
> for
> > + * sharing amongst servlets.
> > + */
> > +public abstract class CrossServletState {
> > +  private static final Logger logger
> > +      = Logger.getLogger("org.apache.shindig.gadgets");
> > +  /**
> > +   * @param config
> > +   * @return A CrossServletState appropriate for the given
> ServletConfig
> > +   * @throws ServletException
> > +   */
> > +  public static synchronized CrossServletState get(ServletConfig
> config)
> > +      throws ServletException {
> > +    ServletContext context = config.getServletContext();
> > +    // Check to see if the context has already been created. If it has,
> > +    // just return.
> > +    CrossServletState state
> > +        = (CrossServletState)context.getAttribute("servlet-data");
> > +
> > +    if (state == null) {
> > +      String dataClass = context.getInitParameter
> ("servlet-data-class");
> > +      if (dataClass  == null) {
> > +        throw new ServletException("servlet-data-class is missing.");
> > +      }
> > +      logger.info("Loading CrossServletState: " + dataClass);
> > +      try {
> > +        state  =
> > (CrossServletState)Class.forName(dataClass).newInstance();
> > +        state.init(context);
> > +        context.setAttribute("servlet-data", state);
> > +      } catch (InstantiationException ie) {
> > +        throw new ServletException(ie);
> > +      } catch (IllegalAccessException iae) {
> > +        throw new ServletException(iae);
> > +      } catch (ClassNotFoundException cnfe) {
> > +        throw new ServletException(cnfe);
> > +      }
> > +    }
> > +    return state;
> > +  }
> > +
> > +  /**
> > +   * @return A GadgetServer instance that is fully configured and
> > +   * ready to be used to process gadgets.
> > +   */
> > +  public abstract GadgetServer getGadgetServer();
> > +
> > +  /**
> > +   * @param req The request that a signing token is needed for.
> > +   * @return A unique GadgetSigner for the request
> > +   */
> > +  public abstract GadgetSigner getGadgetSigner(HttpServletRequest req);
> > +
> > +  /**
> > +   * Constructs a url for retrieving javascript for the given
> > +   * set of features.
> > +   *
> > +   * @param features
> > +   * @return The url to retrieve the appropriate JS.
> > +   */
> > +  public abstract String getJsUrl(String[] features);
> > +
> > +  /**
> > +   * Constructs a url for generating an iframe for the given gadget.
> > +   * This only applies for RPC calls that must generate an iframe.
> > +   */
> > +  public abstract String getIframeUrl(Gadget gadget,
>  HttpServletRequest
> > req);
> > +
> > +  /**
> > +   * Initializes this handler using the provided implementation.
> > +   * @param context
> > +   * @throws ServletException
> > +   */
> > +  protected abstract void init(ServletContext context) throws
> > ServletException;
> > +}
> >
> > Added:
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java?rev=619684&view=auto
> >
> >
> ==============================================================================
> > ---
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
> > (added)
> > +++
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
> > Thu Feb  7 15:18:30 2008
> > @@ -0,0 +1,192 @@
> > +/*
> > + * Licensed to the Apache Software Foundation (ASF) under one
> > + * or more contributor license agreements.  See the NOTICE file
> > + * distributed with this work for additional information
> > + * regarding copyright ownership.  The ASF licenses this file
> > + * to you 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.shindig.gadgets.http;
> > +
> > +import org.apache.shindig.gadgets.BasicGadgetDataCache;
> > +import org.apache.shindig.gadgets.BasicGadgetSigner;
> > +import org.apache.shindig.gadgets.BasicRemoteContentFetcher;
> > +import org.apache.shindig.gadgets.Gadget;
> > +import org.apache.shindig.gadgets.GadgetException;
> > +import org.apache.shindig.gadgets.GadgetFeatureFactory;
> > +import org.apache.shindig.gadgets.GadgetFeatureRegistry;
> > +import org.apache.shindig.gadgets.GadgetServer;
> > +import org.apache.shindig.gadgets.GadgetServerConfig;
> > +import org.apache.shindig.gadgets.GadgetSigner;
> > +import org.apache.shindig.gadgets.GadgetSpec;
> > +import org.apache.shindig.gadgets.JsLibrary;
> > +import org.apache.shindig.gadgets.JsLibraryFeatureFactory;
> > +import org.apache.shindig.gadgets.MessageBundle;
> > +import org.apache.shindig.gadgets.RenderingContext;
> > +
> > +import java.io.UnsupportedEncodingException;
> > +import java.net.URLEncoder;
> > +import java.security.MessageDigest;
> > +import java.security.NoSuchAlgorithmException;
> > +import java.util.Map;
> > +import java.util.concurrent.Executors;
> > +
> > +import javax.servlet.ServletContext;
> > +import javax.servlet.ServletException;
> > +import javax.servlet.http.HttpServletRequest;
> > +
> > +/**
> > + * A handler which uses all of the basic versions of classes.
> > + */
> > +public class DefaultCrossServletState extends CrossServletState {
> > +
> > +  private GadgetServer gadgetServer;
> > +  private GadgetSigner gadgetSigner;
> > +  private String jsPath;
> > +  private String iframePath;
> > +  private String jsCacheParam;
> > +
> > +  private static final String DEFAULT_JS_PREFIX = "/gadgets/js/";
> > +  private static final String DEFAULT_IFRAME_PREFIX  = "/gadgets/ifr?";
> > +
> > +  /**
> > +   * {@inheritDoc}
> > +   */
> > +  @Override
> > +  public GadgetServer getGadgetServer() {
> > +    return gadgetServer;
> > +  }
> > +
> > +  /**
> > +   * {@inheritDoc}
> > +   * Just returns the same gadget signer no matter the request.
> > +   */
> > +  @Override
> > +  public GadgetSigner getGadgetSigner(HttpServletRequest req) {
> > +    return gadgetSigner;
> > +  }
> > +
> > +  /**
> > +   * {@inheritDoc}
> > +   */
> > +  @Override
> > +  public String getIframeUrl(Gadget gadget, HttpServletRequest req) {
> > +    // We don't have any meaningful data in the current request anyway,
> > so
> > +    // we'll just do this statically.
> > +    StringBuilder buf = new StringBuilder();
> > +    try {
> > +      buf.append(iframePath)
> > +          .append("url=")
> > +          .append(
> > +              URLEncoder.encode(gadget.getId
> > ().getURI().toString(),"UTF-8"));
> > +    } catch (UnsupportedEncodingException e) {
> > +      throw new RuntimeException("UTF-8 Not supported!", e);
> > +    }
> > +
> > +    // TODO: extract user prefs, current view, etc. from <req>.
> Currently
> > +    // consumers of the response are on their own for this.
> > +    return buf.toString();
> > +  }
> > +
> > +  /**
> > +   * {@inheritDoc}
> > +   */
> > +  @Override
> > +  public String getJsUrl(String[] features) {
> > +    StringBuilder buf = new StringBuilder();
> > +    buf.append(jsPath);
> > +    if (features == null || features.length == 0) {
> > +      buf.append("core");
> > +    } else {
> > +      boolean firstDone = false;
> > +      for (String feature : features) {
> > +        if (firstDone) {
> > +          buf.append(":");
> > +        } else {
> > +          firstDone = true;
> > +        }
> > +        buf.append(feature);
> > +      }
> > +    }
> > +    buf.append(".js?v=").append(jsCacheParam);
> > +    return buf.toString();
> > +  }
> > +
> > +  /**
> > +   * {@inheritDoc}
> > +   */
> > +  @Override
> > +  protected void init(ServletContext context) throws ServletException {
> > +    jsPath = context.getInitParameter("js-service-path");
> > +    if (jsPath == null) {
> > +      jsPath = DEFAULT_JS_PREFIX;
> > +    }
> > +
> > +    iframePath = context.getInitParameter("iframe-path");
> > +    if (iframePath == null) {
> > +      iframePath = DEFAULT_IFRAME_PREFIX;
> > +    }
> > +
> > +    // features could be null, but that would probably be a bad idea.
> > +    String features = context.getInitParameter("features");
> > +    try {
> > +      gadgetSigner = new BasicGadgetSigner();
> > +      GadgetFeatureRegistry registry = new
> > GadgetFeatureRegistry(features);
> > +      GadgetServerConfig config =  new GadgetServerConfig()
> > +          .setExecutor(Executors.newCachedThreadPool())
> > +          .setMessageBundleCache(new
> > BasicGadgetDataCache<MessageBundle>())
> > +          .setSpecCache(new BasicGadgetDataCache<GadgetSpec>())
> > +          .setContentFetcher(new BasicRemoteContentFetcher(1024 *
> 1024))
> > +          .setFeatureRegistry(registry);
> > +      gadgetServer = new GadgetServer(config);
> > +
> > +      // Grab all static javascript, concatenate it together, and
> > generate
> > +      // an md5. This becomes the cache busting suffix for javascript
> > files.
> > +      StringBuilder jsBuf = new StringBuilder();
> > +
> > +      for (Map.Entry<String, GadgetFeatureRegistry.Entry> entry :
> > +          registry.getAllFeatures().entrySet()) {
> > +        GadgetFeatureFactory factory = entry.getValue().getFeature();
> > +        if (factory instanceof JsLibraryFeatureFactory) {
> > +          JsLibraryFeatureFactory lib =
> (JsLibraryFeatureFactory)factory;
> > +          for (RenderingContext rc : RenderingContext.values()) {
> > +            for (JsLibrary library : lib.getLibraries(rc)) {
> > +              jsBuf.append(library.getContent());
> > +            }
> > +          }
> > +        }
> > +      }
> > +      MessageDigest md;
> > +      try {
> > +        md = MessageDigest.getInstance("MD5");
> > +      } catch (NoSuchAlgorithmException noMD5) {
> > +        try {
> > +          md = MessageDigest.getInstance("SHA");
> > +        } catch (NoSuchAlgorithmException noSha) {
> > +          throw new ServletException("No suitable MessageDigest
> found!");
> > +        }
> > +      }
> > +      byte[] hash = md.digest(jsBuf.toString().getBytes());
> > +      // Convert to hex. This might be a waste of bytes (32) -- could
> be
> > +      // replaced with a base64 implementation.
> > +      StringBuffer hexString = new StringBuffer();
> > +      for (byte b : hash) {
> > +        hexString.append(Integer.toHexString(0xFF & b));
> > +      }
> > +      jsCacheParam = hexString.toString();
> > +    } catch (GadgetException e) {
> > +      throw new ServletException(e);
> > +    }
> > +  }
> > +}
> >
> > Modified:
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java?rev=619684&r1=619683&r2=619684&view=diff
> >
> >
> ==============================================================================
> > ---
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java
> > (original)
> > +++
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingServlet.java
> > Thu Feb  7 15:18:30 2008
> > @@ -13,18 +13,13 @@
> >  */
> >  package org.apache.shindig.gadgets.http;
> >
> > -import org.apache.shindig.gadgets.BasicGadgetDataCache;
> > -import org.apache.shindig.gadgets.BasicRemoteContentFetcher;
> >  import org.apache.shindig.gadgets.Gadget;
> >  import org.apache.shindig.gadgets.GadgetContentFilter;
> >  import org.apache.shindig.gadgets.GadgetException;
> > -import org.apache.shindig.gadgets.GadgetFeatureRegistry;
> >  import org.apache.shindig.gadgets.GadgetServer;
> > -import org.apache.shindig.gadgets.GadgetServerConfig;
> >  import org.apache.shindig.gadgets.GadgetSpec;
> >  import org.apache.shindig.gadgets.GadgetView;
> >  import org.apache.shindig.gadgets.JsLibrary;
> > -import org.apache.shindig.gadgets.MessageBundle;
> >  import org.apache.shindig.gadgets.ProcessingOptions;
> >  import org.apache.shindig.gadgets.RenderingContext;
> >  import org.apache.shindig.gadgets.UserPrefs;
> > @@ -39,11 +34,11 @@
> >  import java.util.LinkedList;
> >  import java.util.List;
> >  import java.util.Map;
> > -import java.util.Set;
> > -import java.util.concurrent.Executors;
> > +import java.util.logging.Level;
> > +import java.util.logging.Logger;
> >
> >  import javax.servlet.ServletConfig;
> > -import javax.servlet.ServletContext;
> > +import javax.servlet.ServletException;
> >  import javax.servlet.http.HttpServlet;
> >  import javax.servlet.http.HttpServletRequest;
> >  import javax.servlet.http.HttpServletResponse;
> > @@ -52,63 +47,17 @@
> >  * Servlet for rendering Gadgets, typically in an IFRAME.
> >  */
> >  public class GadgetRenderingServlet extends HttpServlet {
> > -  private final GadgetServer gadgetServer;
> > -  private final GadgetServerConfig serverConfig;
> > -  private String jsServicePath;
> > +  private CrossServletState servletState;
> >   private static final String CAJA_PARAM = "caja";
> >   private static final String USERPREF_PARAM_PREFIX = "up_";
> >   private static final String LIBS_PARAM_NAME = "libs";
> > -  private static final String JS_FILE_SUFFIX = ".js";
> > -  public static final String DEFAULT_JS_SERVICE_PATH = "js/";
> > +  private static final Logger logger
> > +      = Logger.getLogger("org.apache.shindig.gadgets");
> >
> > -  /**
> > -   * Creates a {@code GadgetRenderingServlet} with default executor,
> > -   * caches, etc.
> > -   *
> > -   * Note that features aren't loaded until init() is called.
> > -   *
> > -   * @throws GadgetException If something went wrong during
> > configuration.
> > -   */
> > -  public GadgetRenderingServlet() throws GadgetException {
> > -    serverConfig = new GadgetServerConfig()
> > -        .setExecutor(Executors.newCachedThreadPool())
> > -        .setMessageBundleCache(new
> BasicGadgetDataCache<MessageBundle>())
> > -        .setSpecCache(new BasicGadgetDataCache<GadgetSpec>())
> > -        .setContentFetcher(new BasicRemoteContentFetcher(1024 * 1024))
> > -        .setFeatureRegistry(new GadgetFeatureRegistry(null));
> > -    gadgetServer = new GadgetServer(serverConfig);
> > -  }
> > -
> > -  /**
> > -   * Creates a servlet using a pre-configured server. Using this method
> > -   * will cause init to ignore feature loading parameters.
> > -   * @param server
> > -   */
> > -  public GadgetRenderingServlet(GadgetServer server) {
> > -    gadgetServer = server;
> > -    // Set this to null to indicate that all configuration has been
> done
> > -    // custom.
> > -    serverConfig = null;
> > -  }
> >
> >   @Override
> > -  public void init(ServletConfig config) {
> > -    ServletContext context = config.getServletContext();
> > -    String jsPath = context.getInitParameter("js-service-path");
> > -    if (jsPath == null) {
> > -      jsPath = DEFAULT_JS_SERVICE_PATH;
> > -    }
> > -    jsServicePath = jsPath;
> > -    if (serverConfig != null) {
> > -      // Using the default server.
> > -      String features = context.getInitParameter("features");
> > -      try {
> > -        serverConfig.getFeatureRegistry().registerFeatures(features);
> > -      } catch (GadgetException e) {
> > -        e.printStackTrace();
> > -        System.exit(1);
> > -      }
> > -    }
> > +  public void init(ServletConfig config) throws ServletException {
> > +    servletState = CrossServletState.get(config);
> >   }
> >
> >   @Override
> > @@ -153,11 +102,9 @@
> >     String view = req.getParameter("view");
> >     view = (view == null || view.length() == 0) ?
> GadgetSpec.DEFAULT_VIEW: view;
> >     try {
> > -      gadget = gadgetServer.processGadget(gadgetId,
> > -                                          getPrefsFromRequest(req),
> > -                                          context.getLocale(),
> > -                                          RenderingContext.GADGET,
> > -                                          options);
> > +      gadget = servletState.getGadgetServer().processGadget(gadgetId,
> > +          getPrefsFromRequest(req), context.getLocale(),
> > +          RenderingContext.GADGET, options);
> >       outputGadget(gadget, view, options, contentFilters, resp);
> >     } catch (GadgetServer.GadgetProcessException e) {
> >       outputErrors(e, resp);
> > @@ -188,12 +135,6 @@
> >     case URL:
> >       outputUrlGadget(gadget, options, resp);
> >       break;
> > -    // default makes no sense here, as this is an enum, we want to
> insure
> > that
> > -    // we cover all cases of the enum, so leave it out.
> > -//    default:
> > -//      resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
> > -//                     "Unexpected reror: unknown gadget type");
> > -//      break;
> >     }
> >   }
> >
> > @@ -218,6 +159,7 @@
> >
> >     StringBuilder markup = new StringBuilder();
> >     markup.append("<html><head>");
> > +    // TODO: This is so wrong.
> >     markup.append("<style type=\"text/css\">" +
> >                   "body,td,div,span,p{font-family:arial,sans-serif;}" +
> >                   "a {color:#0000cc;}a:visited {color:#551a8b;}" +
> > @@ -228,6 +170,7 @@
> >     StringBuilder externJs = new StringBuilder();
> >     StringBuilder inlineJs = new StringBuilder();
> >     String externFmt = "<script src=\"%s\"></script>\n";
> > +    String forcedLibs = options.getForcedJsLibs();
> >
> >     for (JsLibrary library : gadget.getJsLibraries()) {
> >       JsLibrary.Type type = library.getType();
> > @@ -239,18 +182,17 @@
> >         inlineJs.append(library.getContent()).append('\n');
> >       } else {
> >         // FILE or RESOURCE
> > -        if (options.getForcedJsLibs() == null) {
> > +        if (forcedLibs == null) {
> >           inlineJs.append(library.getContent()).append('\n');
> >         } // otherwise it was already included by options.forceJsLibs.
> >       }
> >     }
> >
> >     // Forced libs first.
> > -    if (options.getForcedJsLibs() != null) {
> > -      markup.append(String.format(externFmt,
> > -                                  DEFAULT_JS_SERVICE_PATH +
> > -                                  options.getForcedJsLibs() +
> > -                                  JS_FILE_SUFFIX));
> > +
> > +    if (forcedLibs != null) {
> > +      String[] libs = forcedLibs.split(":");
> > +      markup.append(String.format(externFmt, servletState.getJsUrl
> > (libs)));
> >     }
> >
> >     if (inlineJs.length() > 0) {
> > @@ -280,7 +222,7 @@
> >         }
> >       }
> >     }
> > -
> > +
> >     if (gadgetExceptions.size() > 0) {
> >       throw new GadgetServer.GadgetProcessException(gadgetExceptions);
> >     }
> > @@ -294,28 +236,31 @@
> >
> >   private void outputUrlGadget(Gadget gadget,
> >       ProcessingOptions options, HttpServletResponse resp) throws
> > IOException {
> > -    // UserPrefs portion of query string to tack on
> >     // TODO: generalize this as injectedArgs on Gadget object
> > +
> > +    // Preserve existing query string parameters.
> > +    URI redirURI = gadget.getContentHref();
> > +    StringBuilder query = new StringBuilder(redirURI.getQuery());
> > +
> >     // TODO: userprefs on the fragment rather than query string
> > -    String prefsQuery = getPrefsQueryString(gadget.getUserPrefValues
> ());
> > -    String libsQuery = null;
> > +    query.append(getPrefsQueryString(gadget.getUserPrefValues()));
> >
> > -    if (options.getForcedJsLibs() == null) {
> > -      libsQuery = getLibsQueryString(gadget.getRequires().keySet());
> > +    String[] libs;
> > +    String forcedLibs = options.getForcedJsLibs();
> > +    if (forcedLibs == null) {
> > +      libs = (String[])gadget.getRequires().keySet().toArray();
> >     } else {
> > -      libsQuery = DEFAULT_JS_SERVICE_PATH +
> > -                  options.getForcedJsLibs() +
> > -                  JS_FILE_SUFFIX;
> > +      libs = forcedLibs.split(":");
> >     }
> > +    appendLibsToQuery(libs, query);
> >
> > -    URI redirURI = gadget.getContentHref();
> >     try {
> >       redirURI = new URI(redirURI.getScheme(),
> >                          redirURI.getUserInfo(),
> >                          redirURI.getHost(),
> >                          redirURI.getPort(),
> >                          redirURI.getPath(),
> > -                         redirURI.getQuery() + prefsQuery + libsQuery,
> > +                         query.toString(),
> >                          redirURI.getFragment());
> >     } catch (URISyntaxException e) {
> >       // Not really ever going to happen; input values are already OK.
> > @@ -337,6 +282,10 @@
> >       markup.append(' ');
> >       markup.append(error.getMessage());
> >       markup.append('\n');
> > +
> > +      // Log the errors here for now. We might want different severity
> > levels
> > +      // for different error codes.
> > +      logger.log(Level.INFO, "Failed to render gadget", error);
> >     }
> >     markup.append("</pre>");
> >     markup.append("</body></html>");
> > @@ -363,9 +312,9 @@
> >       buf.append('&');
> >       try {
> >         buf.append(USERPREF_PARAM_PREFIX)
> > -               .append(URLEncoder.encode(prefEntry.getKey(), "UTF8"))
> > -               .append('=')
> > -               .append(URLEncoder.encode(prefEntry.getValue(),
> "UTF8"));
> > +           .append(URLEncoder.encode(prefEntry.getKey(), "UTF8"))
> > +           .append("=")
> > +           .append(URLEncoder.encode(prefEntry.getValue(), "UTF8"));
> >       } catch (UnsupportedEncodingException e) {
> >         // If UTF8 is somehow not supported, we may as well bail.
> >         // Not a whole lot we can do without such support.
> > @@ -375,26 +324,16 @@
> >     return buf.toString();
> >   }
> >
> > -  private String getLibsQueryString(Set<String> features) {
> > -    StringBuilder buf = new StringBuilder();
> > -    buf.append('&').append(LIBS_PARAM_NAME).append('=');
> > -    buf.append(jsServicePath);
> > -    if (features.size() == 0) {
> > -      buf.append("core");
> > -    } else {
> > -      boolean first = true;
> > -      for (String feature : features) {
> > -        if (first) {
> > -          first = false;
> > -        } else {
> > -          buf.append(':');
> > -        }
> > -        buf.append(feature);
> > -      }
> > -    }
> > -    buf.append(JS_FILE_SUFFIX);
> > -
> > -    return buf.toString();
> > +  /**
> > +   * Appends libs to the query string.
> > +   * @param libs
> > +   * @param query
> > +   */
> > +  private void appendLibsToQuery(String[] libs, StringBuilder query) {
> > +    query.append("&")
> > +         .append(LIBS_PARAM_NAME)
> > +         .append("=")
> > +         .append(servletState.getJsUrl(libs));
> >   }
> >
> >   /**
> >
> > Modified:
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java?rev=619684&r1=619683&r2=619684&view=diff
> >
> >
> ==============================================================================
> > ---
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java
> > (original)
> > +++
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java
> > Thu Feb  7 15:18:30 2008
> > @@ -13,7 +13,6 @@
> >  */
> >  package org.apache.shindig.gadgets.http;
> >
> > -import org.apache.shindig.gadgets.GadgetException;
> >  import org.apache.shindig.gadgets.GadgetFeatureFactory;
> >  import org.apache.shindig.gadgets.GadgetFeatureRegistry;
> >  import org.apache.shindig.gadgets.JsLibrary;
> > @@ -26,7 +25,7 @@
> >  import java.util.Set;
> >
> >  import javax.servlet.ServletConfig;
> > -import javax.servlet.ServletContext;
> > +import javax.servlet.ServletException;
> >  import javax.servlet.http.HttpServlet;
> >  import javax.servlet.http.HttpServletRequest;
> >  import javax.servlet.http.HttpServletResponse;
> > @@ -36,42 +35,24 @@
> >  * Used by type=URL gadgets in loading JavaScript resources.
> >  */
> >  public class JsServlet extends HttpServlet {
> > -  private GadgetFeatureRegistry registry = null;
> > -
> > -  /**
> > -   * Create a JsServlet using a pre-configured feature registry.
> > -   * @param registry
> > -   */
> > -  public JsServlet(GadgetFeatureRegistry registry) {
> > -    this.registry = registry;
> > -  }
> > -
> > -  /**
> > -   * Creates a JsServlet without a default registry; the registry will
> be
> > -   * created automatically when init is called.
> > -   */
> > -  public JsServlet() {
> > -    registry = null;
> > -  }
> > +  private CrossServletState servletState;
> > +  private static final long START_TIME = System.currentTimeMillis();
> >
> >   @Override
> > -  public void init(ServletConfig config) {
> > -    ServletContext context = config.getServletContext();
> > -
> > -    if (registry == null) {
> > -      String features = context.getInitParameter("features");
> > -      try {
> > -        registry = new GadgetFeatureRegistry(features);
> > -      } catch (GadgetException e) {
> > -        e.printStackTrace();
> > -        throw new RuntimeException(e);
> > -      }
> > -    }
> > +  public void init(ServletConfig config) throws ServletException {
> > +    servletState = CrossServletState.get(config);
> >   }
> >
> >   @Override
> >   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
> >       throws IOException {
> > +    // If an If-Modified-Since header is ever provided, we always say
> > +    // not modified. This is because when there actually is a change,
> > +    // cache busting should occur.
> > +    if (req.getHeader("If-Modified-Since") != null) {
> > +      resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
> > +      return;
> > +    }
> >     // Use the last component as filename; prefix is ignored
> >     String uri = req.getRequestURI();
> >     // We only want the file name part. There will always be at least 1
> > slash
> > @@ -94,6 +75,8 @@
> >         = new HashSet<GadgetFeatureRegistry.Entry>();
> >     Set<String> missing = new HashSet<String>();
> >
> > +    GadgetFeatureRegistry registry
> > +        = servletState.getGadgetServer
> > ().getConfig().getFeatureRegistry();
> >     if (registry.getIncludedFeatures(needed, found, missing)) {
> >       String containerParam = req.getParameter("c");
> >       RenderingContext context;
> > @@ -105,6 +88,8 @@
> >
> >       Set<GadgetFeatureRegistry.Entry> done
> >           = new HashSet<GadgetFeatureRegistry.Entry>();
> > +
> > +      // TODO: This doesn't work correctly under JDK 1.5, but it does
> > under 1.6
> >       do {
> >         for (GadgetFeatureRegistry.Entry entry : found) {
> >           if (!done.contains(entry) &&
> > @@ -145,8 +130,15 @@
> >    * @param response The HTTP response
> >    */
> >   private void setCachingHeaders(HttpServletResponse response) {
> > -    response.setHeader("Cache-Control", "public,max-age=2592000");
> > -    response.setDateHeader("Expires", System.currentTimeMillis()
> > -                                     + 2592000000L);
> > +
> > +    // Most browsers accept this. 2030 is the last round year before
> > +    // the end of time.
> > +    response.setHeader("Expires", "Tue, 01 Jan 2030 00:00:01 GMT");
> > +
> > +    // IE seems to need this (10 years should be enough).
> > +    response.setHeader("Cache-Control", "public,max-age=315360000");
> > +
> > +    // Firefox requires this for certain cases.
> > +    response.setDateHeader("Last-Modified", START_TIME);
> >   }
> >  }
> >
> > Modified:
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java?rev=619684&r1=619683&r2=619684&view=diff
> >
> >
> ==============================================================================
> > ---
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
> > (original)
> > +++
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
> > Thu Feb  7 15:18:30 2008
> > @@ -18,7 +18,6 @@
> >  */
> >  package org.apache.shindig.gadgets.http;
> >
> > -import org.apache.shindig.gadgets.BasicRemoteContentFetcher;
> >  import org.apache.shindig.gadgets.GadgetException;
> >  import org.apache.shindig.gadgets.GadgetSigner;
> >  import org.apache.shindig.gadgets.GadgetToken;
> > @@ -48,13 +47,9 @@
> >   private static final int TWO_HOURS_IN_MS = 7200000;
> >   private static final int ONE_HOUR_IN_SECS = 3600;
> >   private static final int MAX_PROXY_SIZE = 1024 * 1024;
> > -
> > +
> >   private final RemoteContentFetcher fetcher;
> >
> > -  public ProxyHandler() {
> > -    this(new BasicRemoteContentFetcher(MAX_PROXY_SIZE));
> > -  }
> > -
> >   public ProxyHandler(RemoteContentFetcher fetcher) {
> >     this.fetcher = fetcher;
> >   }
> > @@ -203,7 +198,9 @@
> >   private GadgetToken extractAndValidateToken(HttpServletRequest
> request,
> >       GadgetSigner signer) throws ServletException {
> >     try {
> > -      if (signer == null) return null;
> > +      if (signer == null) {
> > +        return null;
> > +      }
> >       String token = request.getParameter("st");
> >       if (token == null) {
> >         token = "";
> > @@ -229,7 +226,7 @@
> >
> >   /**
> >    * Sign a URL with a GadgetToken if needed
> > -   * @return
> > +   * @return
> >    */
> >   private URL signUrl(URL originalUrl, GadgetToken token,
> >       HttpServletRequest request) throws ServletException {
> > @@ -238,7 +235,7 @@
> >           !"signed".equals(request.getParameter("authz"))) {
> >         return originalUrl;
> >       }
> > -      return token.signUrl(originalUrl, "GET", // TODO:
> request.getMethod
> > ()
> > +      return token.signUrl(originalUrl, "GET", // TODO:
> request.getMethod
> > ()
> >           request.getParameterMap());
> >     } catch (GadgetException ge) {
> >       throw new ServletException(ge);
> >
> > Modified:
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java?rev=619684&r1=619683&r2=619684&view=diff
> >
> >
> ==============================================================================
> > ---
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
> > (original)
> > +++
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
> > Thu Feb  7 15:18:30 2008
> > @@ -18,28 +18,38 @@
> >  */
> >  package org.apache.shindig.gadgets.http;
> >
> > -import org.apache.shindig.gadgets.BasicGadgetSigner;
> > -import org.apache.shindig.gadgets.GadgetSigner;
> > +import org.apache.shindig.gadgets.GadgetServerConfigReader;
> >
> >  import java.io.IOException;
> >
> > +import javax.servlet.ServletConfig;
> >  import javax.servlet.ServletException;
> >  import javax.servlet.http.HttpServlet;
> >  import javax.servlet.http.HttpServletRequest;
> >  import javax.servlet.http.HttpServletResponse;
> >
> >  public class ProxyServlet extends HttpServlet {
> > -  private final GadgetSigner signer;
> > -  private final ProxyHandler handler;
> > +  private CrossServletState servletState;
> > +  private ProxyHandler proxyHandler;
> > +
> > +  @Override
> > +  public void init(ServletConfig config) throws ServletException {
> > +    servletState = CrossServletState.get(config);
> > +    GadgetServerConfigReader serverConfig
> > +        = servletState.getGadgetServer().getConfig();
> > +    proxyHandler = new ProxyHandler(serverConfig.getContentFetcher());
> > +  }
> >
> >   @Override
> >   protected void doGet(HttpServletRequest request, HttpServletResponse
> > response)
> >       throws ServletException, IOException {
> >     String output = request.getParameter("output");
> >     if ("js".equals(output)) {
> > -      handler.fetchJson(request, response, signer);
> > +      proxyHandler.fetchJson(
> > +          request, response, servletState.getGadgetSigner(request));
> >     } else {
> > -      handler.fetch(request, response, signer);
> > +      proxyHandler.fetch(
> > +          request, response, servletState.getGadgetSigner(request));
> >     }
> >   }
> >
> > @@ -48,22 +58,5 @@
> >       throws ServletException, IOException {
> >     // Currently they are identical
> >     doGet(request, response);
> > -  }
> > -
> > -  /**
> > -   * Constructs a ProxyServlet with the default (non-secure)
> > GadgetSigner.
> > -   */
> > -  public ProxyServlet() {
> > -    this(new BasicGadgetSigner(), new ProxyHandler());
> > -  }
> > -
> > -  /**
> > -   * Creates a ProxyServlet using the specified GadgetSigner.
> > -   * @param signer Used to sign and verify requests
> > -   * @param handler Used to fetch proxied content
> > -   */
> > -  public ProxyServlet(GadgetSigner signer, ProxyHandler handler) {
> > -    this.signer = signer;
> > -    this.handler = handler;
> >   }
> >  }
> >
> > Added:
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java?rev=619684&view=auto
> >
> >
> ==============================================================================
> > ---
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java
> > (added)
> > +++
> >
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java
> > Thu Feb  7 15:18:30 2008
> > @@ -0,0 +1,48 @@
> > +/*
> > + * Licensed to the Apache Software Foundation (ASF) under one
> > + * or more contributor license agreements.  See the NOTICE file
> > + * distributed with this work for additional information
> > + * regarding copyright ownership.  The ASF licenses this file
> > + * to you 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.shindig.gadgets.http;
> > +
> > +import java.io.IOException;
> > +
> > +import javax.servlet.ServletConfig;
> > +import javax.servlet.ServletException;
> > +import javax.servlet.http.HttpServlet;
> > +import javax.servlet.http.HttpServletRequest;
> > +import javax.servlet.http.HttpServletResponse;
> > +
> > +/**
> > + * Handles RPC metadata requests.
> > + */
> > +public class RpcServlet extends HttpServlet {
> > +  private CrossServletState state;
> > +
> > +  @Override
> > +  protected void doGet(HttpServletRequest request, HttpServletResponse
> > response)
> > +      throws ServletException, IOException {
> > +  }
> > +
> > +  @Override
> > +  public void init(ServletConfig config) throws ServletException {
> > +    state = CrossServletState.get(config);
> > +  }
> > +
> > +  public RpcServlet() {
> > +  }
> > +}
> >
> > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml?rev=619684&r1=619683&r2=619684&view=diff
> >
> >
> ==============================================================================
> > --- incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml
> > (original)
> > +++ incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml
> > Thu Feb  7 15:18:30 2008
> > @@ -19,48 +19,63 @@
> >         "http://java.sun.com/dtd/web-app_2_3.dtd">
> >
> >  <web-app>
> > -    <!-- configuration -->
> > -    <context-param>
> > -        <param-name>features</param-name>
> > -        <param-value>res://features/features.txt</param-value>
> > -    </context-param>
> > -
> > -    <!-- Render a Gadget -->
> > -    <servlet>
> > -        <servlet-name>xml-to-html</servlet-name>
> > -        <servlet-class>
> > -            org.apache.shindig.gadgets.http.GadgetRenderingServlet
> > -        </servlet-class>
> > -    </servlet>
> > -
> > -    <!-- Proxy -->
> > -    <servlet>
> > -        <servlet-name>proxy</servlet-name>
> > -        <servlet-class>
> > -            org.apache.shindig.gadgets.http.ProxyServlet
> > -        </servlet-class>
> > -    </servlet>
> > -
> > -
> > -    <!-- javascript serving -->
> > -    <servlet>
> > -        <servlet-name>js</servlet-name>
> > -        <servlet-class>org.apache.shindig.gadgets.http.JsServlet
> > </servlet-class>
> > -    </servlet>
> > -
> > -    <servlet-mapping>
> > -        <servlet-name>js</servlet-name>
> > -        <url-pattern>/js/*</url-pattern>
> > -    </servlet-mapping>
> > -
> > -    <servlet-mapping>
> > -        <servlet-name>proxy</servlet-name>
> > -        <url-pattern>/proxy</url-pattern>
> > -    </servlet-mapping>
> > -
> > -    <servlet-mapping>
> > -        <servlet-name>xml-to-html</servlet-name>
> > -        <url-pattern>/ifr</url-pattern>
> > -    </servlet-mapping>
> > -
> > +  <!-- configuration -->
> > +  <context-param>
> > +    <param-name>features</param-name>
> > +    <param-value>res://features/features.txt</param-value>
> > +  </context-param>
> > +  <context-param>
> > +    <param-name>servlet-data-class</param-name>
> > +    <param-value>
> org.apache.shindig.gadgets.http.DefaultCrossServletState
> > </param-value>
> > +  </context-param>
> > +
> > +  <!-- Render a Gadget -->
> > +  <servlet>
> > +    <servlet-name>xml-to-html</servlet-name>
> > +    <servlet-class>
> > +      org.apache.shindig.gadgets.http.GadgetRenderingServlet
> > +    </servlet-class>
> > +  </servlet>
> > +
> > +  <!-- Proxy -->
> > +  <servlet>
> > +    <servlet-name>proxy</servlet-name>
> > +    <servlet-class>
> > +      org.apache.shindig.gadgets.http.ProxyServlet
> > +    </servlet-class>
> > +  </servlet>
> > +
> > +  <!-- Metadata RPC -->
> > +  <servlet>
> > +    <servlet-name>rpc</servlet-name>
> > +    <servlet-class>
> > +      org.apache.shindig.gadgets.http.RpcServlet
> > +    </servlet-class>
> > +  </servlet>
> > +
> > +  <!-- javascript serving -->
> > +  <servlet>
> > +    <servlet-name>js</servlet-name>
> > +    <servlet-class>org.apache.shindig.gadgets.http.JsServlet
> > </servlet-class>
> > +  </servlet>
> > +
> > +  <servlet-mapping>
> > +    <servlet-name>js</servlet-name>
> > +    <url-pattern>/js/*</url-pattern>
> > +  </servlet-mapping>
> > +
> > +  <servlet-mapping>
> > +    <servlet-name>proxy</servlet-name>
> > +    <url-pattern>/proxy</url-pattern>
> > +  </servlet-mapping>
> > +
> > +  <servlet-mapping>
> > +    <servlet-name>xml-to-html</servlet-name>
> > +    <url-pattern>/ifr</url-pattern>
> > +  </servlet-mapping>
> > +
> > +  <servlet-mapping>
> > +    <servlet-name>rpc</servlet-name>
> > +    <url-pattern>/rpc</url-pattern>
> > +  </servlet-mapping>
> >  </web-app>
> >
> > Modified:
> >
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
> > URL:
> >
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java?rev=619684&r1=619683&r2=619684&view=diff
> >
> >
> ==============================================================================
> > ---
> >
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
> > (original)
> > +++
> >
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
> > Thu Feb  7 15:18:30 2008
> > @@ -27,29 +27,48 @@
> >  import static org.easymock.EasyMock.expect;
> >  import static org.easymock.EasyMock.isA;
> >
> > -import java.util.concurrent.Executor;
> >  import java.util.concurrent.Executors;
> >
> >  public class GadgetServerTest extends EasyMockTestCase {
> > -  final Executor executor = Executors.newCachedThreadPool();
> > -  final GadgetServer gadgetServer;
> > +  GadgetServer gadgetServer;
> >   final RemoteContentFetcher fetcher = mock(RemoteContentFetcher.class);
> >   @SuppressWarnings(value="unchecked")
> >   final GadgetDataCache<GadgetSpec> specCache = mock(
> GadgetDataCache.class
> > );
> >   @SuppressWarnings(value="unchecked")
> >   final GadgetDataCache<MessageBundle> bundleCache = mock(
> > GadgetDataCache.class);
> >
> > -  public GadgetServerTest() throws GadgetException {
> > -    // TODO: need to test for configuration errors.
> > -    gadgetServer = new GadgetServer(new GadgetServerConfig()
> > -        .setExecutor(executor)
> > -        .setSpecCache(specCache)
> > -        .setMessageBundleCache(bundleCache)
> > -        .setFeatureRegistry(new GadgetFeatureRegistry(null))
> > -        .setContentFetcher(fetcher));
> > +  void initServer(GadgetServerConfigReader customConfig) throws
> > GadgetException {
> > +    GadgetServerConfig config = new GadgetServerConfig();
> > +
> > +    if (customConfig != null) {
> > +      config.copyFrom(customConfig);
> > +    }
> > +
> > +    if (config.getExecutor() == null) {
> > +      config.setExecutor(Executors.newCachedThreadPool());
> > +    }
> > +
> > +    if (config.getSpecCache() == null) {
> > +      config.setSpecCache(specCache);
> > +    }
> > +
> > +    if (config.getMessageBundleCache() == null) {
> > +      config.setMessageBundleCache(bundleCache);
> > +    }
> > +
> > +    if (config.getFeatureRegistry() == null) {
> > +      config.setFeatureRegistry(new GadgetFeatureRegistry(null));
> > +    }
> > +
> > +    if (config.getContentFetcher() == null) {
> > +      config.setContentFetcher(fetcher);
> > +    }
> > +
> > +    gadgetServer = new GadgetServer(config);
> >   }
> >
> >   public void testGadgetSpecNotInCache() throws Exception {
> > +    initServer(null);
> >     RemoteContent results = new RemoteContent(200,
> > DATETIME_XML.getBytes(), null);
> >     ProcessingOptions options = new ProcessingOptions();
> >
> > @@ -65,6 +84,7 @@
> >   }
> >
> >   public void testGadgetSpecInCache() throws Exception {
> > +    initServer(null);
> >     expect(specCache.get
> > (eq(DATETIME_URI_STRING))).andReturn(DATETIME_SPEC);
> >     replay();
> >
> > @@ -75,6 +95,7 @@
> >   }
> >
> >   public void testBasicGadget() throws Exception {
> > +    initServer(null);
> >     RemoteContent results = new RemoteContent(200,
> > DATETIME_XML.getBytes(), null);
> >     ProcessingOptions options = new ProcessingOptions();
> >
> > @@ -93,8 +114,7 @@
> >
> >   public void testBlacklistedGadget() throws Exception {
> >     GadgetBlacklist blacklist = mock(GadgetBlacklist.class);
> > -    gadgetServer.setGadgetBlacklist(blacklist);
> > -
> > +    initServer(new GadgetServerConfig().setGadgetBlacklist(blacklist));
> >     expect(specCache.get(eq(DATETIME_URI_STRING))).andReturn(null);
> >     expect(blacklist.isBlacklisted(eq(DATETIME_URI))).andReturn(true);
> >     replay();
> >
> >
> >
>