You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by Santiago Gala <sa...@gmail.com> on 2008/04/04 01:35:17 UTC

Re: svn commit: r644123 [1/3] - in /incubator/shindig/trunk: features/core.io/ java/gadgets/ java/gadgets/conf/ java/gadgets/src/main/java/org/apache/shindig/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ java/gadgets/src/main/j

El jue, 03-04-2008 a las 11:46 -0700, Kevin Brown escribió:
> Those files should have been removed entirely (the code was moved or is
> simply unnecessary). I clearly don't understand SVN well enough yet to be
> using it!

I committed the removal, not every day I can get the credit of
contributing 0 lines of java code in 8 different files. :)

Regards
Santiago

> 
> On Thu, Apr 3, 2008 at 11:23 AM, Santiago Gala <sa...@gmail.com>
> wrote:
> 
> > quite possibly a small oversight after applying the patch, but
> >
> > $ find . -name .svn -prune -or -type f -empty -print
> >
> > ./java/gadgets/src/test/java/org/apache/shindig/gadgets/http/GadgetRendererTest.java
> >
> > ./java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcRequestTest.java
> >
> > ./java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadgetJob.java
> >
> > ./java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcRequest.java
> >
> > ./java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfig.java
> >
> > ./java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.java
> >
> > :) (I am not sure it is not a working copy problem here)
> >
> > Regards
> > Santiago
> >
> >
> > El jue, 03-04-2008 a las 00:40 +0000, etnu@apache.org escribió:
> > > Author: etnu
> > > Date: Wed Apr  2 17:40:05 2008
> > > New Revision: 644123
> > >
> > > URL: http://svn.apache.org/viewvc?rev=644123&view=rev
> > > Log:
> > > Wiring up Guice support as discussed in SHINDIG-152.
> > >
> > > This is a very significant change for anyone who has maintained
> > customized implementations of any of the core Shindig classes, but it
> > greatly simplifies the task of extending te server.
> > >
> > > This patch also incorporates Brian Eaton's signing interface
> > improvements discussed in SHINDIG-157.
> > >
> > >
> > > Added:
> > >     incubator/shindig/trunk/java/gadgets/conf/
> > >     incubator/shindig/trunk/java/gadgets/conf/gadgets.properties
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetTokenDecoder.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/CachedContentFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetTokenDecoder.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/PreloadFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcherFactory.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderingTask.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GuiceServletContextListener.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpGuiceModule.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/InjectedServlet.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcHandler.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxiedContentFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/UrlGenerator.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/InterceptingContentFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SigningFetcherTest.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/GadgetRenderingTaskTest.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpTestFixture.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcHandlerTest.java
> > > Removed:
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetSigner.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DataFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetSigner.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/NullRequestSigner.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigner.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SignedFetchRequestSigner.java
> > >
> > 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/test/java/org/apache/shindig/gadgets/SignedFetchRequestSignerTest.java
> > > Modified:
> > >     incubator/shindig/trunk/features/core.io/io.js
> > >     incubator/shindig/trunk/java/gadgets/pom.xml
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetBlacklist.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/Gadget.java
> > >
> > 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/GadgetServerConfig.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetSpecFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContent.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RenderingContext.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SyndicatorConfig.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/GadgetRenderer.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/JsonRpcGadgetContext.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadgetJob.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcRequest.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/java/org/apache/shindig/gadgets/http/RpcServlet.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Preload.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/GadgetDataServlet.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/BlobCrypter.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/ResourceLoader.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/EasyMockTestCase.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsLibraryTest.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/GadgetRendererTest.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcRequestTest.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/ProxyHandlerTest.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/ModulePrefsTest.java
> > >
> > incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/util/BlobCrypterTest.java
> > >
> > > Modified: incubator/shindig/trunk/features/core.io/io.js
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core.io/io.js?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > --- incubator/shindig/trunk/features/core.io/io.js (original)
> > > +++ incubator/shindig/trunk/features/core.io/io.js Wed Apr  2 17:40:05
> > 2008
> > > @@ -193,10 +193,10 @@
> > >     *         false otherwise
> > >     */
> > >    function respondWithPreload(postData, params, callback) {
> > > -    if (gadgets.io.preloaded && gadgets.io.preloaded[postData.url]) {
> > > -      var preload = gadgets.io.preloaded[postData.url];
> > > +    if (gadgets.io.preloaded_ && gadgets.io.preloaded_[postData.url]) {
> > > +      var preload = gadgets.io.preloaded_[postData.url];
> > >        if (postData.httpMethod == "GET" && postData.authz == "none") {
> > > -        delete gadgets.io.preloaded[postData.url];
> > > +        delete gadgets.io.preloaded_[postData.url];
> > >          if (preload.rc !== 200) {
> > >            callback({errors : ["Error " + preload.rc]});
> > >          } else {
> > > @@ -349,4 +349,4 @@
> > >
> > >  gadgets.io.AuthorizationType = gadgets.util.makeEnum([
> > >    "NONE", "SIGNED", "AUTHENTICATED"
> > > -]);
> > > \ No newline at end of file
> > > +]);
> > >
> > > Added: incubator/shindig/trunk/java/gadgets/conf/gadgets.properties
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/conf/gadgets.properties?rev=644123&view=auto
> > >
> > ==============================================================================
> > > --- incubator/shindig/trunk/java/gadgets/conf/gadgets.properties (added)
> > > +++ incubator/shindig/trunk/java/gadgets/conf/gadgets.properties Wed Apr
> >  2 17:40:05 2008
> > > @@ -0,0 +1,9 @@
> > > +features.default=res://features/features.txt
> > > +syndicators.default=res://syndicators/default/syndicator.js
> > > +blacklist.file=
> > > +urls.iframe.prefix=/gadgets/ifr?
> > > +urls.js.prefix=/gadgets/js/
> > > +signing.key-name=
> > > +signing.key-file=
> > > +
> > > +
> > >
> > > Modified: incubator/shindig/trunk/java/gadgets/pom.xml
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/pom.xml?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > --- incubator/shindig/trunk/java/gadgets/pom.xml (original)
> > > +++ incubator/shindig/trunk/java/gadgets/pom.xml Wed Apr  2 17:40:05
> > 2008
> > > @@ -153,13 +153,6 @@
> > >          <directory>../../features</directory>
> > >        </resource>
> > >        <resource>
> > > -        <targetPath>syndicators/default</targetPath>
> > > -        <directory>../../config</directory>
> > > -        <includes>
> > > -          <include>syndicator.js</include>
> > > -        </includes>
> > > -      </resource>
> > > -      <resource>
> > >          <!-- duplicated here for the jar build. -->
> > >          <!-- TODO: Eliminate duplicate copies in WAR output -->
> > >          <!-- this is relative to the pom.xml directory -->
> > > @@ -169,6 +162,16 @@
> > >            <include>**/*.*</include>
> > >          </includes>
> > >        </resource>
> > > +      <resource>
> > > +        <targetPath>syndicators/default</targetPath>
> > > +        <directory>../../config</directory>
> > > +        <includes>
> > > +          <include>syndicator.js</include>
> > > +        </includes>
> > > +      </resource>
> > > +      <resource>
> > > +        <directory>conf</directory>
> > > +      </resource>
> > >      </resources>
> > >    </build>
> > >    <repositories>
> > > @@ -229,7 +232,12 @@
> > >        <version>20080229</version>
> > >        <scope>compile</scope>
> > >      </dependency>
> > > -             <dependency>
> > > +  <dependency>
> > > +      <groupId>com.google.code.guice</groupId>
> > > +      <artifactId>guice</artifactId>
> > > +      <version>1.0</version>
> > > +    </dependency>
> > > +    <dependency>
> > >        <groupId>commons-lang</groupId>
> > >        <artifactId>commons-lang</artifactId>
> > >        <version>2.3</version>
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetBlacklist.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetBlacklist.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetBlacklist.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetBlacklist.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -17,6 +17,9 @@
> > >   */
> > >  package org.apache.shindig.gadgets;
> > >
> > > +import com.google.inject.Inject;
> > > +import com.google.inject.name.Named;
> > > +
> > >  import java.io.BufferedReader;
> > >  import java.io.File;
> > >  import java.io.FileReader;
> > > @@ -71,7 +74,15 @@
> > >    public BasicGadgetBlacklist(File blacklistFile) throws IOException {
> > >      exactMatches = new HashSet<String>();
> > >      regexpMatches = new ArrayList<Pattern>();
> > > -    parseBlacklist(blacklistFile);
> > > +    if (blacklistFile.exists()) {
> > > +      parseBlacklist(blacklistFile);
> > > +    }
> > > +  }
> > > +
> > > +  @Inject
> > > +  public BasicGadgetBlacklist(@Named("blacklist.file") String file)
> > > +      throws IOException {
> > > +    this(new File(file));
> > >    }
> > >
> > >    private void parseBlacklist(File blacklistFile) throws IOException {
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -27,24 +27,24 @@
> > >  /**
> > >   * Primitive token implementation that uses stings as tokens.
> > >   */
> > > -class BasicGadgetToken implements GadgetToken {
> > > +public class BasicGadgetToken implements GadgetToken {
> > >    /** serialized form of the token */
> > >    private final String token;
> > > -
> > > +
> > >    /** data from the token */
> > >    private final Map<String, String> tokenData;
> > > -
> > > +
> > >    /** tool to use for signing and encrypting the token */
> > >    private BlobCrypter crypter = new BlobCrypter(INSECURE_KEY);
> > > -
> > > +
> > >    private static final byte[] INSECURE_KEY =
> > >      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
> > > -
> > > +
> > >    private static final String OWNER_KEY = "o";
> > >    private static final String APP_KEY = "a";
> > >    private static final String VIEWER_KEY = "v";
> > >    private static final String DOMAIN_KEY = "d";
> > > -
> > > +
> > >    /**
> > >     * {@inheritDoc}
> > >     */
> > > @@ -56,14 +56,14 @@
> > >     * Generates a token from an input string
> > >     * @param token String form of token
> > >     * @param maxAge max age of the token (in seconds)
> > > -   * @throws BlobCrypterException
> > > +   * @throws BlobCrypterException
> > >     */
> > >    public BasicGadgetToken(String token, int maxAge)
> > > -  throws BlobCrypterException {
> > > +      throws BlobCrypterException {
> > >      this.token = token;
> > >      this.tokenData = crypter.unwrap(token, maxAge);
> > >    }
> > > -
> > > +
> > >    public BasicGadgetToken(String owner, String viewer, String app,
> > >        String domain) throws BlobCrypterException {
> > >      tokenData = new HashMap<String, String>(5,1);
> > >
> > > Added:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetTokenDecoder.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetTokenDecoder.java?rev=644123&view=auto
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetTokenDecoder.java
> > (added)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetTokenDecoder.java
> > Wed Apr  2 17:40:05 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;
> > > +
> > > +import org.apache.shindig.util.BlobCrypterException;
> > > +
> > > +/**
> > > + * A GadgetTokenDecoder implementation that just provides dummy data to
> > satisfy
> > > + * tests and API calls. Do not use this for any security applications.
> > > + */
> > > +public class BasicGadgetTokenDecoder implements GadgetTokenDecoder {
> > > +
> > > +  /**
> > > +   * {@inheritDoc}
> > > +   *
> > > +   * Returns a token with some faked out values.
> > > +   */
> > > +  public GadgetToken createToken(String stringToken) throws
> > GadgetException {
> > > +    try {
> > > +      String[] tokens = stringToken.split(":");
> > > +      return new BasicGadgetToken(tokens[0], tokens[1], tokens[2],
> > tokens[3]);
> > > +    } catch (BlobCrypterException e) {
> > > +      throw new
> > GadgetException(GadgetException.Code.INVALID_GADGET_TOKEN, e);
> > > +    }
> > > +  }
> > > +
> > > +  /**
> > > +   * Creates a signer with 24 hour token expiry
> > > +   */
> > > +  public BasicGadgetTokenDecoder() {
> > > +  }
> > > +}
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -19,19 +19,28 @@
> > >
> > >  import org.apache.shindig.util.InputStreamConsumer;
> > >
> > > +import com.google.inject.Singleton;
> > > +
> > >  import java.io.FileNotFoundException;
> > >  import java.io.IOException;
> > > +import java.io.InputStream;
> > >  import java.net.HttpURLConnection;
> > >  import java.net.URLConnection;
> > >  import java.util.List;
> > >  import java.util.Map;
> > > +import java.util.zip.GZIPInputStream;
> > > +import java.util.zip.Inflater;
> > > +import java.util.zip.InflaterInputStream;
> > >
> > >  /**
> > >   * Implementation of a {@code RemoteObjectFetcher} using standard
> > java.net
> > > - * classes.
> > > + * classes. Only one instance of this should be present at any time, so
> > we
> > > + * annotate it as a Singleton to resolve Guice injection limitations.
> > >   */
> > > -public class BasicRemoteContentFetcher implements RemoteContentFetcher
> > {
> > > +@Singleton
> > > +public class BasicRemoteContentFetcher extends RemoteContentFetcher {
> > >    private static final int CONNECT_TIMEOUT_MS = 5000;
> > > +  private static final int DEFAULT_MAX_OBJECT_SIZE = 1024 * 1024;
> > >
> > >    private final int maxObjSize;
> > >
> > > @@ -41,10 +50,18 @@
> > >     * @param maxObjSize Maximum size, in bytes, of object to fetch
> > >     */
> > >    public BasicRemoteContentFetcher(int maxObjSize) {
> > > +    super(null);
> > >      this.maxObjSize = maxObjSize;
> > >    }
> > >
> > >    /**
> > > +   * Creates a new fetcher using the default maximum object size.
> > > +   */
> > > +  public BasicRemoteContentFetcher() {
> > > +    this(DEFAULT_MAX_OBJECT_SIZE);
> > > +  }
> > > +
> > > +  /**
> > >     * Initializes the connection.
> > >     *
> > >     * @param request
> > > @@ -56,6 +73,7 @@
> > >      URLConnection fetcher;
> > >      fetcher = request.getUri().toURL().openConnection();
> > >      fetcher.setConnectTimeout(CONNECT_TIMEOUT_MS);
> > > +    fetcher.setRequestProperty("Accept-Encoding", "gzip, deflate");
> > >      if (fetcher instanceof HttpURLConnection) {
> > >        ((HttpURLConnection)fetcher).setInstanceFollowRedirects(true);
> > >        Map<String, List<String>> reqHeaders = request.getAllHeaders();
> > > @@ -96,12 +114,25 @@
> > >      } else {
> > >        responseCode = RemoteContent.SC_OK;
> > >      }
> > > -    byte[] body = InputStreamConsumer.readToByteArray(
> > > -        fetcher.getInputStream(), maxObjSize);
> > > +
> > > +    String encoding = fetcher.getContentEncoding();
> > > +    InputStream is = null;
> > > +    // Create the appropriate stream wrapper based on the encoding
> > type.
> > > +    if (encoding == null) {
> > > +      is =  fetcher.getInputStream();
> > > +    } else if (encoding.equalsIgnoreCase("gzip")) {
> > > +      is = new GZIPInputStream(fetcher.getInputStream());
> > > +    } else if (encoding.equalsIgnoreCase("deflate")) {
> > > +      Inflater inflater = new Inflater(true);
> > > +      is = new InflaterInputStream(fetcher.getInputStream(), inflater);
> > > +    }
> > > +
> > > +    byte[] body = InputStreamConsumer.readToByteArray(is, maxObjSize);
> > >      return new RemoteContent(responseCode, body, headers);
> > >    }
> > >
> > >    /** {@inheritDoc} */
> > > +  @Override
> > >    public RemoteContent fetch(RemoteContentRequest request) {
> > >      try {
> > >        URLConnection fetcher = getConnection(request);
> > >
> > > Added:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/CachedContentFetcher.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/CachedContentFetcher.java?rev=644123&view=auto
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/CachedContentFetcher.java
> > (added)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/CachedContentFetcher.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -0,0 +1,57 @@
> > > +/*
> > > + * 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;
> > > +
> > > +import com.google.inject.Inject;
> > > +import com.google.inject.Singleton;
> > > +
> > > +import java.net.URI;
> > > +import java.util.HashMap;
> > > +import java.util.Map;
> > > +
> > > +/**
> > > + * Caches the results of a request indefinitely.
> > > + *
> > > + * Currently just uses a map for the cache. This means it will grow
> > infinitely.
> > > + */
> > > +@Singleton
> > > +public class CachedContentFetcher extends RemoteContentFetcher {
> > > +
> > > +  private final Map<URI, RemoteContent> cache;
> > > +
> > > +  /** {@inheritDoc} */
> > > +  @Override
> > > +  public RemoteContent fetch(RemoteContentRequest request)
> > > +      throws GadgetException {
> > > +    RemoteContent result = cache.get(request.getUri());
> > > +    if (result == null) {
> > > +      result = nextFetcher.fetch(request);
> > > +      synchronized (cache) {
> > > +        cache.put(request.getUri(),result);
> > > +      }
> > > +    }
> > > +    return result;
> > > +  }
> > > +
> > > +  @Inject
> > > +  public CachedContentFetcher(RemoteContentFetcher nextFetcher) {
> > > +    super(nextFetcher);
> > > +    cache = new HashMap<URI, RemoteContent>();
> > > +  }
> > > +}
> > >
> > > Added:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java?rev=644123&view=auto
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java
> > (added)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -0,0 +1,92 @@
> > > +/*
> > > + * 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;
> > > +
> > > +import org.apache.shindig.util.ResourceLoader;
> > > +
> > > +import com.google.inject.AbstractModule;
> > > +import com.google.inject.CreationException;
> > > +import com.google.inject.Scopes;
> > > +import com.google.inject.name.Names;
> > > +import com.google.inject.spi.Message;
> > > +
> > > +import java.io.IOException;
> > > +import java.io.InputStream;
> > > +import java.util.Arrays;
> > > +import java.util.Properties;
> > > +import java.util.concurrent.Executor;
> > > +import java.util.concurrent.Executors;
> > > +
> > > +/**
> > > + * Creates a module to supply all of the Basic* classes
> > > + */
> > > +public class DefaultGuiceModule extends AbstractModule {
> > > +  private final Properties properties;
> > > +  private final static String DEFAULT_PROPERTIES =
> > "gadgets.properties";
> > > +
> > > +  /** {@inheritDoc} */
> > > +  @Override
> > > +  protected void configure() {
> > > +    Names.bindProperties(this.binder(), properties);
> > > +
> > > +
> >  bind(RemoteContentFetcher.class).to(BasicRemoteContentFetcher.class);
> > > +
> > > +    bind(RemoteContentFetcher.class)
> > > +        .annotatedWith(GadgetSpecFetcher.class)
> > > +        .to(CachedContentFetcher.class);
> > > +    bind(RemoteContentFetcher.class)
> > > +        .annotatedWith(MessageBundleFetcher.class)
> > > +        .to(CachedContentFetcher.class);
> > > +
> > > +    // This is redundant because Guice doesn't handle generic fall
> > through
> > > +    // for non-annotated types.
> > > +    bind(RemoteContentFetcher.class)
> > > +        .annotatedWith(PreloadFetcher.class)
> > > +        .to(BasicRemoteContentFetcher.class);
> > > +
> > > +    bind(GadgetBlacklist.class).to(BasicGadgetBlacklist.class);
> > > +    bind(GadgetTokenDecoder.class).to(BasicGadgetTokenDecoder.class);
> > > +    bind(SigningFetcherFactory.class);
> > > +    bind(Executor.class).toInstance(Executors.newCachedThreadPool());
> > > +
> > > +    bind(SyndicatorConfig.class).in(Scopes.SINGLETON);
> > > +    bind(GadgetFeatureRegistry.class).in(Scopes.SINGLETON);
> > > +    bind(GadgetServer.class).in(Scopes.SINGLETON);
> > > +  }
> > > +
> > > +  public DefaultGuiceModule(Properties properties) {
> > > +    this.properties = properties;
> > > +  }
> > > +
> > > +  /**
> > > +   * Creates module with standard properties.
> > > +   */
> > > +  public DefaultGuiceModule() {
> > > +    Properties properties = null;
> > > +    try {
> > > +      InputStream is = ResourceLoader.openResource(DEFAULT_PROPERTIES);
> > > +      properties = new Properties();
> > > +      properties.load(is);
> > > +    } catch (IOException e) {
> > > +      throw new CreationException(Arrays.asList(
> > > +          new Message("Unable to load properties: " +
> > DEFAULT_PROPERTIES)));
> > > +    }
> > > +    this.properties = properties;
> > > +  }
> > > +}
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/Gadget.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/Gadget.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/Gadget.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/Gadget.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -34,14 +34,6 @@
> > >   * and is modified in parallel by a number of {@code GadgetFeature}
> > >   * processors, in an order defined by their dependencies, in
> > >   * {@code GadgetServer}.
> > > - *
> > > - * Upon completion of processing, a {@code Gadget} is serialized as
> > appropriate
> > > - * to whatever output format is appropriate (eg. as gadget content in
> > an
> > > - * IFRAME), potentially with post-processing such as HTML whitespace
> > > - * compression or HTML+JS (Caja) rewriting applied.
> > > - *
> > > - * "Hangman" variable substitutions (eg. __MSG_foo__) are performed as
> > needed
> > > - * and transparently for fields that support this functionality.
> > >   */
> > >  public class Gadget {
> > >    private final GadgetContext context;
> > >
> > > 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=644123&r1=644122&r2=644123&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
> > Wed Apr  2 17:40:05 2008
> > > @@ -17,10 +17,12 @@
> > >   */
> > >  package org.apache.shindig.gadgets;
> > >
> > > +import com.google.inject.Inject;
> > > +import com.google.inject.name.Named;
> > > +
> > >  import java.util.Collections;
> > >  import java.util.HashMap;
> > >  import java.util.HashSet;
> > > -import java.util.LinkedList;
> > >  import java.util.List;
> > >  import java.util.Map;
> > >  import java.util.Set;
> > > @@ -35,66 +37,33 @@
> > >   * registry.register("my-feature", null, new MyFeatureFactory());
> > >   */
> > >  public class GadgetFeatureRegistry {
> > > -  private final Map<String, Entry> features = new HashMap<String,
> > Entry>();
> > > -  private final Map<String, Entry> core =  new HashMap<String,
> > Entry>();
> > > +  private final Map<String, Entry> features;
> > > +  private final Map<String, Entry> core;
> > >
> > >    // Caches the transitive dependencies to enable faster lookups.
> > >    private final Map<Set<String>, Set<Entry>> transitiveDeps
> > >        = new HashMap<Set<String>, Set<Entry>>();
> > >
> > > -  private boolean coreDone = false;
> > > -
> > > -  private final RemoteContentFetcher fetcher;
> > > +  private boolean graphComplete = false;
> > >
> > >    private final static Logger logger
> > >        = Logger.getLogger("org.apache.shindig.gadgets");
> > >
> > >    /**
> > > -   * Creates the gadget feature registry and loads an initial set of
> > features.
> > > -   * Any 'core' features loaded at this point will automatically become
> > > -   * dependencies for every other feature.
> > > -   * @param featurePath
> > > -   * @param fetcher
> > > -   */
> > > -  public GadgetFeatureRegistry(String featurePath, RemoteContentFetcher
> > fetcher)
> > > -      throws GadgetException {
> > > -    this.fetcher = fetcher;
> > > -    registerFeatures(featurePath);
> > > -  }
> > > -
> > > -  /**
> > > -   * Recursively loads a set of features from a path in the filesystem
> > or
> > > -   * from the classpath.
> > > +   * Creates a new feature registry and loads the specified features.
> > >     *
> > > -   * @param featurePath Path to the directory that contains feature xml
> > files.
> > > -   */
> > > -  public void registerFeatures(String featurePath) throws
> > GadgetException {
> > > -    if (featurePath == null) {
> > > -      return;
> > > -    }
> > > -
> > > -    List<String> coreDeps = new LinkedList<String>();
> > > -    JsFeatureLoader loader = new JsFeatureLoader(fetcher);
> > > -    Set<Entry> jsFeatures = loader.loadFeatures(featurePath, this);
> > > -
> > > -    if (!coreDone) {
> > > -      for (Entry entry : jsFeatures) {
> > > -        if (entry.name.startsWith("core") || entry.name.equals("core"))
> > {
> > > -          coreDeps.add(entry.getName());
> > > -          core.put(entry.getName(), entry);
> > > -        }
> > > -      }
> > > -
> > > -      logger.info("Core dependencies: " + coreDeps);
> > > -
> > > -      // Make sure non-core features depend on core.
> > > -      for (Entry entry : jsFeatures) {
> > > -        if (!entry.name.startsWith("core") &&
> > !entry.name.equals("core")) {
> > > -          entry.deps.addAll(core.keySet());
> > > -        }
> > > -      }
> > > -
> > > -      coreDone = true;
> > > +   * @param contentFetcher
> > > +   * @param featureFiles
> > > +   * @throws GadgetException
> > > +   */
> > > +  @Inject
> > > +  public GadgetFeatureRegistry(@Named("features.default") String
> > featureFiles,
> > > +      RemoteContentFetcher contentFetcher) throws GadgetException {
> > > +    features = new HashMap<String, Entry>();
> > > +    core = new HashMap<String, Entry>();
> > > +    if (featureFiles != null) {
> > > +      JsFeatureLoader loader = new JsFeatureLoader(contentFetcher);
> > > +      loader.loadFeatures(featureFiles, this);
> > >      }
> > >    }
> > >
> > > @@ -105,7 +74,9 @@
> > >     *
> > >     * Names are freeform, but it is strongly suggested that they are
> > >     * namespaced, optionally (yet often usefully) in Java
> > package-notation ie.
> > > -   * 'com.google.gadgets.skins'.
> > > +   * 'org.example.FooFeature'
> > > +   *
> > > +   * May never be invoked after calling getIncludedFeatures.
> > >     *
> > >     * @param name Name of the feature to register, ideally using the
> > conventions
> > >     *     described
> > > @@ -116,26 +87,33 @@
> > >     */
> > >    public Entry register(String name, List<String> deps,
> > >                          GadgetFeatureFactory feature) {
> > > +    if (graphComplete) {
> > > +      throw new IllegalStateException("registerFeatures should never be
> > " +
> > > +          "invoked after calling getIncludedFeatures");
> > > +    }
> > >      logger.info("Registering feature: " + name + " with deps " + deps);
> > >      Entry entry = new Entry(name, deps, feature, this);
> > > -    if (coreDone) {
> > > +    if (isCore(entry)) {
> > > +      core.put(name, entry);
> > > +      for (Entry e : features.values()) {
> > > +        e.deps.add(name);
> > > +      }
> > > +    } else {
> > >        entry.deps.addAll(core.keySet());
> > >      }
> > >      features.put(name, entry);
> > > -    validateFeatureGraph();
> > >      return entry;
> > >    }
> > >
> > >    /**
> > > -   * Traverses the graph traversed by the registered features,
> > validating
> > > -   * that it comprises a directed acyclic graph in which all features'
> > > -   * dependencies are provided.
> > > -   *
> > > -   * If the graph is not acyclic, it cannot be used to create a
> > workflow. If
> > > -   * any dependencies are missing, {@code Gadget} rendering may be
> > incomplete.
> > > +   * @param entry
> > > +   * @return True if the entry is "core" (a dependency of all other
> > features)
> > >     */
> > > -  private static void validateFeatureGraph() {
> > > -    // TODO: ensure that features form a DAG and that all deps are
> > provided
> > > +  private boolean isCore(Entry entry) {
> > > +    if (entry.name.startsWith("core") || entry.name.equals("core")) {
> > > +      return true;
> > > +    }
> > > +    return false;
> > >    }
> > >
> > >    /**
> > > @@ -158,6 +136,7 @@
> > >    public boolean getIncludedFeatures(Set<String> needed,
> > >                                       Set<Entry> resultsFound,
> > >                                       Set<String> resultsMissing) {
> > > +    graphComplete = true;
> > >      if (needed.size() == 0) {
> > >        // Shortcut for gadgets that don't have any explicit
> > dependencies.
> > >        resultsFound.addAll(core.values());
> > >
> > > 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=644123&r1=644122&r2=644123&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
> > Wed Apr  2 17:40:05 2008
> > > @@ -22,7 +22,8 @@
> > >  import org.apache.shindig.gadgets.spec.LocaleSpec;
> > >  import org.apache.shindig.gadgets.spec.MessageBundle;
> > >  import org.apache.shindig.gadgets.spec.Preload;
> > > -import org.apache.shindig.util.Check;
> > > +
> > > +import com.google.inject.Inject;
> > >
> > >  import java.util.HashMap;
> > >  import java.util.HashSet;
> > > @@ -32,39 +33,42 @@
> > >  import java.util.Set;
> > >  import java.util.concurrent.Callable;
> > >  import java.util.concurrent.CompletionService;
> > > +import java.util.concurrent.Executor;
> > >  import java.util.concurrent.ExecutorCompletionService;
> > >  import java.util.concurrent.Future;
> > >
> > > +/**
> > > + * Primary gadget processing facility. Converts an input Context into
> > an output
> > > + * Gadget
> > > + */
> > >  public class GadgetServer {
> > > -  private final GadgetServerConfigReader config;
> > > -
> > > -  /**
> > > -   * Creates a GadgetServer using the provided configuration.
> > > -   *
> > > -   * @param configuration
> > > -   * @throws IllegalArgumentException When missing required fields
> > aren't set.
> > > -   */
> > > -  public GadgetServer(GadgetServerConfigReader configuration) {
> > > -    Check.notNull(configuration.getExecutor(), "Executor is
> > required.");
> > > -    Check.notNull(configuration.getFeatureRegistry(),
> > > -        "FeatureRegistry is required.");
> > > -    Check.notNull(configuration.getGadgetSpecFetcher(),
> > > -        "GadgetSpecFetcher is required");
> > > -    Check.notNull(configuration.getMessageBundleFetcher(),
> > > -        "MessageBundleFetcher is required.");
> > > -    Check.notNull(configuration.getContentFetcher(),
> > > -        "ContentFetcher is required.");
> > > -    Check.notNull(configuration.getSyndicatorConfig(),
> > > -        "SyndicatorConfig is required");
> > > -    config = new GadgetServerConfigReader();
> > > -    config.copyFrom(configuration);
> > > -  }
> > > +  private final Executor executor;
> > > +  private final GadgetFeatureRegistry registry;
> > > +  private final GadgetBlacklist blacklist;
> > > +  private final RemoteContentFetcher preloadFetcher;
> > > +  private final RemoteContentFetcher gadgetSpecFetcher;
> > > +  private final RemoteContentFetcher messageBundleFetcher;
> > >
> > >    /**
> > > -   * @return A read-only view of the server's configuration.
> > > +   * @param executor
> > > +   * @param registry
> > > +   * @param blacklist
> > > +   * @param gadgetSpecFetcher
> > > +   * @param messageBundleFetcher
> > >     */
> > > -  public GadgetServerConfigReader getConfig() {
> > > -    return config;
> > > +  @Inject
> > > +  public GadgetServer(Executor executor,
> > > +      GadgetFeatureRegistry registry,
> > > +      GadgetBlacklist blacklist,
> > > +      @PreloadFetcher RemoteContentFetcher preloadFetcher,
> > > +      @GadgetSpecFetcher RemoteContentFetcher gadgetSpecFetcher,
> > > +      @MessageBundleFetcher RemoteContentFetcher messageBundleFetcher)
> > {
> > > +    this.executor = executor;
> > > +    this.registry = registry;
> > > +    this.blacklist = blacklist;
> > > +    this.preloadFetcher = preloadFetcher;
> > > +    this.gadgetSpecFetcher = gadgetSpecFetcher;
> > > +    this.messageBundleFetcher = messageBundleFetcher;
> > >    }
> > >
> > >    /**
> > > @@ -75,13 +79,15 @@
> > >     * @throws GadgetException
> > >     */
> > >    public Gadget processGadget(GadgetContext context) throws
> > GadgetException {
> > > -    if (config.getGadgetBlacklist() != null) {
> > > -      if (config.getGadgetBlacklist().isBlacklisted(context.getUrl()))
> > {
> > > -        throw new
> > GadgetException(GadgetException.Code.BLACKLISTED_GADGET);
> > > -      }
> > > +    if (blacklist.isBlacklisted(context.getUrl())) {
> > > +      throw new
> > GadgetException(GadgetException.Code.BLACKLISTED_GADGET);
> > >      }
> > > -    GadgetSpec spec =
> > config.getGadgetSpecFetcher().fetch(context.getUrl(),
> > > -        context.getIgnoreCache());
> > > +
> > > +    RemoteContentRequest request = RemoteContentRequest.getRequest(
> > > +        context.getUrl(), context.getIgnoreCache());
> > > +    RemoteContent response = gadgetSpecFetcher.fetch(request);
> > > +    GadgetSpec spec
> > > +        = new GadgetSpec(context.getUrl(),
> > response.getResponseAsString());
> > >      return createGadgetFromSpec(spec, context);
> > >    }
> > >
> > > @@ -94,9 +100,10 @@
> > >     */
> > >    private MessageBundle getBundle(LocaleSpec localeSpec, GadgetContext
> > context)
> > >        throws GadgetException {
> > > -    MessageBundle bundle;
> > > -    bundle = config.getMessageBundleFetcher().fetch(
> > > +    RemoteContentRequest request = RemoteContentRequest.getRequest(
> > >          localeSpec.getMessages(), context.getIgnoreCache());
> > > +    RemoteContent response = messageBundleFetcher.fetch(request);
> > > +    MessageBundle bundle = new
> > MessageBundle(response.getResponseAsString());
> > >      return bundle;
> > >    }
> > >
> > > @@ -178,17 +185,22 @@
> > >        Map<GadgetFeatureRegistry.Entry, GadgetFeature> tasks)
> > >        throws GadgetException {
> > >
> > > -    // Immediately enqueue all the preloads
> > > -    CompletionService<RemoteContent> preloadProcessor
> > > -        = new
> > ExecutorCompletionService<RemoteContent>(config.getExecutor());
> > > -    for (Preload preload :
> > gadget.getSpec().getModulePrefs().getPreloads()) {
> > > -      gadget.getPreloadMap().put(preload,
> > > -          preloadProcessor.submit(
> > > -              new PreloadTask(preload,
> > getConfig().getContentFetcher())));
> > > +    // Immediately enqueue all the preloads. We don't block on preloads
> > because
> > > +    // we want them to run in parallel
> > > +    RenderingContext renderContext =
> > gadget.getContext().getRenderingContext();
> > > +    if (RenderingContext.GADGET.equals(renderContext)) {
> > > +      CompletionService<RemoteContent> preloadProcessor
> > > +          = new ExecutorCompletionService<RemoteContent>(executor);
> > > +      for (Preload preload :
> > gadget.getSpec().getModulePrefs().getPreloads()) {
> > > +        PreloadTask task = new PreloadTask(preload, preloadFetcher);
> > > +        Future<RemoteContent> future = preloadProcessor.submit(task);
> > > +        gadget.getPreloadMap().put(preload, future);
> > > +      }
> > >      }
> > >
> > > +    // TODO: This seems pointless if nothing is actually using it.
> > >      CompletionService<GadgetException> featureProcessor
> > > -        = new
> > ExecutorCompletionService<GadgetException>(config.getExecutor());
> > > +        = new ExecutorCompletionService<GadgetException>(executor);
> > >      // FeatureTask is OK has a hash key because we want actual
> > instances, not
> > >      // names.
> > >      GadgetContext context = gadget.getContext();
> > > @@ -251,8 +263,7 @@
> > >      Set<GadgetFeatureRegistry.Entry> dependencies
> > >          = new HashSet<GadgetFeatureRegistry.Entry>(features.size());
> > >      Set<String> unsupported = new HashSet<String>();
> > > -    config.getFeatureRegistry().getIncludedFeatures(features.keySet(),
> > > -        dependencies, unsupported);
> > > +    registry.getIncludedFeatures(features.keySet(), dependencies,
> > unsupported);
> > >
> > >      for (String missing : unsupported) {
> > >        Feature feature = features.get(missing);
> > > @@ -319,7 +330,11 @@
> > >
> > >    public RemoteContent call() {
> > >      RemoteContentRequest request = new
> > RemoteContentRequest(preload.getHref());
> > > -    return fetcher.fetch(request);
> > > +    try {
> > > +      return fetcher.fetch(request);
> > > +    } catch (GadgetException e) {
> > > +      return RemoteContent.ERROR;
> > > +    }
> > >    }
> > >
> > >    public PreloadTask(Preload preload, RemoteContentFetcher fetcher) {
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfig.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfig.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfig.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfig.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -1,88 +0,0 @@
> > > -/**
> > > - * 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;
> > > -
> > > -import org.apache.shindig.gadgets.spec.GadgetSpec;
> > > -import org.apache.shindig.gadgets.spec.MessageBundle;
> > > -
> > > -import java.util.concurrent.Executor;
> > > -
> > > -/**
> > > - * Stores configuration data for a GadgetServer.
> > > - *
> > > - * The main purpose of this class is to allow for better readability of
> > > - * GadgetServer ctor parameters and to simplify interacting with its
> > components.
> > > - *
> > > - *
> > > - *
> > > - * Usage:
> > > - *
> > > - * <code>
> > > - * GadgetServer server = new GadgetServer(new GadgetServerConfig()
> > > - *      .setRemoteContentFetcher(new BasicRemoteContentFetcher())
> > > - *      .setGadgetCache(new BasicGadgetDataCache<GadgetSpec>())
> > > - *      .setOtherProperties(...));
> > > - * </code>
> > > - *
> > > - * Any missing data will result in GadgetServer throwing an
> > IllegalArgsException
> > > - * unless noted as "optional" here.
> > > - */
> > > -public class GadgetServerConfig extends GadgetServerConfigReader  {
> > > -
> > > -  public GadgetServerConfig setExecutor(Executor executor) {
> > > -    this.executor = executor;
> > > -    return this;
> > > -  }
> > > -
> > > -  public GadgetServerConfig setFeatureRegistry(
> > > -      GadgetFeatureRegistry featureRegistry) {
> > > -    this.featureRegistry = featureRegistry;
> > > -    return this;
> > > -  }
> > > -
> > > -  public GadgetServerConfig setGadgetSpecFetcher(
> > > -      DataFetcher<GadgetSpec> gadgetSpecFetcher) {
> > > -    this.gadgetSpecFetcher = gadgetSpecFetcher;
> > > -    return this;
> > > -  }
> > > -
> > > -  public GadgetServerConfig setMessageBundleFetcher(
> > > -      DataFetcher<MessageBundle> messageBundleFetcher) {
> > > -    this.messageBundleFetcher = messageBundleFetcher;
> > > -    return this;
> > > -  }
> > > -
> > > -  public GadgetServerConfig setContentFetcher(
> > > -      RemoteContentFetcher contentFetcher) {
> > > -    this.contentFetcher = contentFetcher;
> > > -    return this;
> > > -  }
> > > -
> > > -  // Optional
> > > -
> > > -  public GadgetServerConfig setGadgetBlacklist(
> > > -      GadgetBlacklist gadgetBlacklist) {
> > > -    this.gadgetBlacklist = gadgetBlacklist;
> > > -    return this;
> > > -  }
> > > -
> > > -  public GadgetServerConfig setSyndicatorConfig(SyndicatorConfig
> > config) {
> > > -    syndicatorConfig = config;
> > > -    return this;
> > > -  }
> > > -}
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -1,96 +0,0 @@
> > > -/**
> > > - * 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;
> > > -
> > > -import org.apache.shindig.gadgets.spec.GadgetSpec;
> > > -import org.apache.shindig.gadgets.spec.MessageBundle;
> > > -
> > > -import java.util.concurrent.Executor;
> > > -
> > > -/**
> > > - * Stores configuration data for a GadgetServer.
> > > - *
> > > - * The main purpose of this class is to allow for better readability of
> > > - * GadgetServer ctor parameters and to simplify interacting with its
> > components.
> > > - *
> > > - * Works in conjunction with {@code GadgetServerConfig} to create
> > immutable
> > > - * configuration objects. Note that members are still potentially
> > mutable.
> > > - *
> > > - */
> > > -public class GadgetServerConfigReader  {
> > > -
> > > -  protected Executor executor;
> > > -
> > > -  public Executor getExecutor() {
> > > -    return executor;
> > > -  }
> > > -
> > > -  protected GadgetFeatureRegistry featureRegistry;
> > > -
> > > -  public GadgetFeatureRegistry getFeatureRegistry() {
> > > -    return featureRegistry;
> > > -  }
> > > -
> > > -  protected DataFetcher<GadgetSpec> gadgetSpecFetcher;
> > > -
> > > -  public DataFetcher<GadgetSpec> getGadgetSpecFetcher() {
> > > -    return gadgetSpecFetcher;
> > > -  }
> > > -
> > > -  protected DataFetcher<MessageBundle> messageBundleFetcher;
> > > -
> > > -  public DataFetcher<MessageBundle> getMessageBundleFetcher() {
> > > -    return messageBundleFetcher;
> > > -  }
> > > -
> > > -  protected RemoteContentFetcher contentFetcher;
> > > -
> > > -  public RemoteContentFetcher getContentFetcher() {
> > > -    return contentFetcher;
> > > -  }
> > > -
> > > -  protected GadgetBlacklist gadgetBlacklist;
> > > -
> > > -  public GadgetBlacklist getGadgetBlacklist() {
> > > -    return gadgetBlacklist;
> > > -  }
> > > -
> > > -  protected SyndicatorConfig syndicatorConfig;
> > > -
> > > -  public SyndicatorConfig getSyndicatorConfig() {
> > > -    if (syndicatorConfig == null) {
> > > -      return SyndicatorConfig.EMPTY;
> > > -    }
> > > -    return syndicatorConfig;
> > > -  }
> > > -
> > > -  /**
> > > -   * Copies all fields from {@code base} into this instance.
> > > -   * @param base
> > > -   */
> > > -  public void copyFrom(GadgetServerConfigReader base) {
> > > -    // We use the getters here just in case any methods were
> > overridden.
> > > -    executor = base.getExecutor();
> > > -    featureRegistry = base.getFeatureRegistry();
> > > -    contentFetcher = base.getContentFetcher();
> > > -    gadgetSpecFetcher = base.getGadgetSpecFetcher();
> > > -    messageBundleFetcher = base.getMessageBundleFetcher();
> > > -    gadgetBlacklist = base.getGadgetBlacklist();
> > > -    syndicatorConfig = base.getSyndicatorConfig();
> > > -  }
> > > -}
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetSpecFetcher.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetSpecFetcher.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetSpecFetcher.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetSpecFetcher.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -19,62 +19,15 @@
> > >
> > >  package org.apache.shindig.gadgets;
> > >
> > > -import org.apache.shindig.gadgets.spec.GadgetSpec;
> > > +import com.google.inject.BindingAnnotation;
> > >
> > > -import java.net.URI;
> > > -import java.util.HashMap;
> > > -import java.util.Map;
> > > -import java.util.logging.Logger;
> > > -
> > > -/**
> > > - * Spec retrieval implementation that retrieves specs by the following:
> > > - *
> > > - * - Consulting the in-memory cache (just a Map)
> > > - * - If not found, making a RemoteContentRequest for the spec
> > > - * - Parsing spec
> > > - * - Storing to the cache
> > > - */
> > > -public class GadgetSpecFetcher implements DataFetcher<GadgetSpec> {
> > > -  private final RemoteContentFetcher fetcher;
> > > -  private final Map<URI, GadgetSpec> cache;
> > > -
> > > -  private final static Logger logger
> > > -      = Logger.getLogger("org.apache.shindig.gadgets");
> > > -
> > > -  /** {@inheritDoc} */
> > > -  public void invalidate(URI url) {
> > > -    synchronized (cache) {
> > > -      cache.remove(url);
> > > -    }
> > > -  }
> > > -
> > > -  /** {@inheritDoc} */
> > > -  public GadgetSpec fetch(URI url, boolean forceReload) throws
> > GadgetException {
> > > -    GadgetSpec spec = null;
> > > -    if (!forceReload) {
> > > -      spec = cache.get(url);
> > > -    }
> > > -    if (spec == null) {
> > > -      RemoteContentRequest request = new RemoteContentRequest(url);
> > > -      RemoteContent response = fetcher.fetch(request);
> > > -
> > > -      if (response.getHttpStatusCode() == RemoteContent.SC_OK) {
> > > -        spec = new GadgetSpec(url, response.getResponseAsString());
> > > -        cache.put(url, spec);
> > > -      } else {
> > > -        String error = "Unable to get content from " + url.toString();
> > > -        throw new GadgetException(
> > > -            GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT, error);
> > > -      }
> > > -    }
> > > -    return spec;
> > > -  }
> > > -
> > > -  /**
> > > -   * @param fetcher The fetcher to use for remote resource retrieval.
> > > -   */
> > > -  public GadgetSpecFetcher(RemoteContentFetcher fetcher) {
> > > -    this.fetcher = fetcher;
> > > -    cache = new HashMap<URI, GadgetSpec>();
> > > -  }
> > > +import java.lang.annotation.ElementType;
> > > +import java.lang.annotation.Retention;
> > > +import java.lang.annotation.RetentionPolicy;
> > > +import java.lang.annotation.Target;
> > > +
> > > +@Retention(RetentionPolicy.RUNTIME)
> > > +@Target({ElementType.FIELD, ElementType.PARAMETER})
> > > +@BindingAnnotation
> > > +public @interface GadgetSpecFetcher {
> > >  }
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -20,7 +20,7 @@
> > >
> > >  /**
> > >   * An abstract representation of a signing token.
> > > - * Use in conjunction with @code GadgetSigner.
> > > + * Use in conjunction with @code GadgetTokenDecoder.
> > >   */
> > >  public interface GadgetToken {
> > >
> > >
> > > Added:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetTokenDecoder.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetTokenDecoder.java?rev=644123&view=auto
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetTokenDecoder.java
> > (added)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetTokenDecoder.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -0,0 +1,34 @@
> > > +/*
> > > + * 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;
> > > +
> > > +/**
> > > + *  Handles verification of gadget security tokens.
> > > + */
> > > +public interface GadgetTokenDecoder {
> > > +
> > > +  /**
> > > +   * Decrypts and verifies a gadget security token to return a gadget
> > token.
> > > +   *
> > > +   * @param tokenString String representation of the token to be
> > created.
> > > +   * @return The token representation of the input data.
> > > +   * @throws GadgetException If tokenString is not a valid token
> > > +   */
> > > +  public GadgetToken createToken(String tokenString) throws
> > GadgetException;
> > > +}
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -26,7 +26,11 @@
> > >
> > >  import java.io.File;
> > >  import java.io.IOException;
> > > -import java.util.*;
> > > +import java.util.EnumMap;
> > > +import java.util.HashMap;
> > > +import java.util.LinkedList;
> > > +import java.util.List;
> > > +import java.util.Map;
> > >  import java.util.logging.Logger;
> > >
> > >  /**
> > > @@ -59,18 +63,18 @@
> > >     *    in the text file. If path is prefixed with res://, the file
> > >     *    is treated as a resource, and all references are assumed to be
> > >     *    resources as well.
> > > -   * @return A list of the newly loaded features.
> > >     * @throws GadgetException
> > >     */
> > > -  public Set<GadgetFeatureRegistry.Entry> loadFeatures(String path,
> > > -      GadgetFeatureRegistry registry) throws GadgetException {
> > > +  public void loadFeatures(String path, GadgetFeatureRegistry registry)
> > > +      throws GadgetException {
> > >      List<ParsedFeature> features = new LinkedList<ParsedFeature>();
> > >      try {
> > >        if (path.startsWith("res://")) {
> > >          path = path.substring(6);
> > >          logger.info("Loading resources from: " + path);
> > >          if (path.endsWith(".txt")) {
> > > -
> >  loadResources(ResourceLoader.getContent(path).split("[\r\n]+"), features);
> > > +
> >  loadResources(ResourceLoader.getContent(path).split("[\r\n]+"),
> > > +              features);
> > >          } else {
> > >            loadResources(new String[]{path}, features);
> > >          }
> > > @@ -83,14 +87,11 @@
> > >        throw new GadgetException(GadgetException.Code.INVALID_PATH, e);
> > >      }
> > >
> > > -    Set<GadgetFeatureRegistry.Entry> entries
> > > -        = new HashSet<GadgetFeatureRegistry.Entry>();
> > >      for (ParsedFeature feature : features) {
> > >        JsLibraryFeatureFactory factory
> > >            = new JsLibraryFeatureFactory(feature.libraries);
> > > -      entries.add(registry.register(feature.name, feature.deps,
> > factory));
> > > +      registry.register(feature.name, feature.deps, factory);
> > >      }
> > > -    return entries;
> > >    }
> > >
> > >    /**
> > > @@ -213,7 +214,8 @@
> > >
> > >      NodeList gadgets = doc.getElementsByTagName("gadget");
> > >      for (int i = 0, j = gadgets.getLength(); i < j; ++i) {
> > > -      processContext(feature, (Element)gadgets.item(i),
> > RenderingContext.GADGET);
> > > +      processContext(feature, (Element)gadgets.item(i),
> > > +          RenderingContext.GADGET);
> > >      }
> > >
> > >      NodeList containers = doc.getElementsByTagName("container");
> > > @@ -236,9 +238,11 @@
> > >     * @param feature
> > >     * @param context
> > >     * @param renderingContext
> > > +   * @throws GadgetException
> > >     */
> > >    private void processContext(ParsedFeature feature, Element context,
> > > -                              RenderingContext renderingContext) {
> > > +                              RenderingContext renderingContext)
> > > +      throws GadgetException {
> > >      String syndicator = XmlUtil.getAttribute(context, "synd",
> > >          SyndicatorConfig.DEFAULT_SYNDICATOR);
> > >      NodeList libraries = context.getElementsByTagName("script");
> > > @@ -298,7 +302,8 @@
> > >    final List<String> deps;
> > >
> > >    public ParsedFeature() {
> > > -    libraries = new EnumMap<RenderingContext, Map<String,
> > List<JsLibrary>>>(RenderingContext.class);
> > > +    libraries = new EnumMap<RenderingContext, Map<String,
> > List<JsLibrary>>>(
> > > +        RenderingContext.class);
> > >      deps = new LinkedList<String>();
> > >    }
> > >
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -113,9 +113,10 @@
> > >     *     kept as a url reference, otherwise the file will be fetched
> > and treated
> > >     *     as a FILE type.
> > >     * @return The newly created library.
> > > +   * @throws GadgetException
> > >     */
> > >    public static JsLibrary create(Type type, String content, String
> > feature,
> > > -      RemoteContentFetcher fetcher) {
> > > +      RemoteContentFetcher fetcher) throws GadgetException {
> > >      String optimizedContent = null;
> > >      String debugContent;
> > >      switch (type) {
> > > @@ -168,9 +169,10 @@
> > >     * @param url
> > >     * @param fetcher
> > >     * @return The contents of the JS file, or null if it can't be
> > fetched.
> > > +   * @throws GadgetException
> > >     */
> > >    private static String loadDataFromUrl(String url,
> > > -      RemoteContentFetcher fetcher) {
> > > +      RemoteContentFetcher fetcher) throws GadgetException {
> > >      try {
> > >        logger.info("Attempting to load js from: " + url);
> > >        URI uri = new URI(url);
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleFetcher.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleFetcher.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleFetcher.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleFetcher.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -19,63 +19,15 @@
> > >
> > >  package org.apache.shindig.gadgets;
> > >
> > > -import org.apache.shindig.gadgets.spec.MessageBundle;
> > > +import com.google.inject.BindingAnnotation;
> > >
> > > -import java.net.URI;
> > > -import java.util.HashMap;
> > > -import java.util.Map;
> > > -import java.util.logging.Logger;
> > > -
> > > -/**
> > > - * Message bundle retrieval implementation that retrieves by the
> > following:
> > > - *
> > > - * - Consulting the in-memory cache (just a Map)
> > > - * - If not found, making a RemoteContentRequest for the bundle
> > > - * - Parsing bundle
> > > - * - Storing to the cache
> > > - */
> > > -public class MessageBundleFetcher implements DataFetcher<MessageBundle>
> > {
> > > -  private final RemoteContentFetcher fetcher;
> > > -  private final Map<URI, MessageBundle> cache;
> > > -
> > > -  private final static Logger logger
> > > -      = Logger.getLogger("org.apache.shindig.gadgets");
> > > -
> > > -  /** {@inheritDoc} */
> > > -  public void invalidate(URI url) {
> > > -    synchronized (cache) {
> > > -      cache.remove(url);
> > > -    }
> > > -  }
> > > -
> > > -  /** {@inheritDoc} */
> > > -  public MessageBundle fetch(URI url, boolean forceReload)
> > > -      throws GadgetException {
> > > -    MessageBundle bundle = null;
> > > -    if (!forceReload) {
> > > -      bundle = cache.get(url);
> > > -    }
> > > -    if (bundle == null) {
> > > -      RemoteContentRequest request = new RemoteContentRequest(url);
> > > -      RemoteContent response = fetcher.fetch(request);
> > > -
> > > -      if (response.getHttpStatusCode() == RemoteContent.SC_OK) {
> > > -        bundle = new MessageBundle(response.getResponseAsString());
> > > -        cache.put(url, bundle);
> > > -      } else {
> > > -        String error = "Unable to get content from " + url.toString();
> > > -        throw new GadgetException(
> > > -            GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT, error);
> > > -      }
> > > -    }
> > > -    return bundle;
> > > -  }
> > > -
> > > -  /**
> > > -   * @param fetcher The fetcher to use for remote resource retrieval.
> > > -   */
> > > -  public MessageBundleFetcher(RemoteContentFetcher fetcher) {
> > > -    this.fetcher = fetcher;
> > > -    cache = new HashMap<URI, MessageBundle>();
> > > -  }
> > > +import java.lang.annotation.ElementType;
> > > +import java.lang.annotation.Retention;
> > > +import java.lang.annotation.RetentionPolicy;
> > > +import java.lang.annotation.Target;
> > > +
> > > +@Retention(RetentionPolicy.RUNTIME)
> > > +@Target({ElementType.FIELD, ElementType.PARAMETER})
> > > +@BindingAnnotation
> > > +public @interface MessageBundleFetcher {
> > >  }
> > >
> > > Added:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/PreloadFetcher.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/PreloadFetcher.java?rev=644123&view=auto
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/PreloadFetcher.java
> > (added)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/PreloadFetcher.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -0,0 +1,33 @@
> > > +/*
> > > + * 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;
> > > +
> > > +import com.google.inject.BindingAnnotation;
> > > +
> > > +import java.lang.annotation.ElementType;
> > > +import java.lang.annotation.Retention;
> > > +import java.lang.annotation.RetentionPolicy;
> > > +import java.lang.annotation.Target;
> > > +
> > > +@Retention(RetentionPolicy.RUNTIME)
> > > +@Target({ElementType.FIELD, ElementType.PARAMETER})
> > > +@BindingAnnotation
> > > +public @interface PreloadFetcher {
> > > +}
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContent.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContent.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContent.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContent.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -89,6 +89,16 @@
> > >    }
> > >
> > >    /**
> > > +   * Simple constructor for setting a basic response from a string.
> > Mostly used
> > > +   * for testing.
> > > +   *
> > > +   * @param body
> > > +   */
> > > +  public RemoteContent(String body) {
> > > +    this(SC_OK, body.getBytes(), null);
> > > +  }
> > > +
> > > +  /**
> > >     * Attempts to determine the encoding of the body. If it can't be
> > determined,
> > >     * we use DEFAULT_ENCODING instead.
> > >     * @return The detected encoding or DEFAULT_ENCODING.
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -18,11 +18,30 @@
> > >  package org.apache.shindig.gadgets;
> > >
> > >
> > > -public interface RemoteContentFetcher {
> > > +/**
> > > + * Fetches data over HTTP.
> > > + *
> > > + * Subclasses can use a chain-of-responsibility pattern to add
> > functionality
> > > + * to the fetching process.  For example, a SigningFetcher can talk to
> > a
> > > + * CachingFetcher can talk to a ThrottlingFetcher that talks to a
> > > + * RemoteFetcher that gets the actual data.
> > > + */
> > > +public abstract class RemoteContentFetcher {
> > > +
> > > +  /** next fetcher in the chain, may be null */
> > > +  protected RemoteContentFetcher nextFetcher;
> > > +
> > > +  protected RemoteContentFetcher(RemoteContentFetcher nextFetcher) {
> > > +    this.nextFetcher = nextFetcher;
> > > +  }
> > > +
> > >    /**
> > > -   * Fetch content using the HTTP GET method
> > > +   * Fetch HTTP content.
> > > +   *
> > >     * @param request The request to fetch.
> > >     * @return RemoteContent
> > > +   * @throws GadgetException
> > >     */
> > > -  public RemoteContent fetch(RemoteContentRequest request);
> > > +  public abstract RemoteContent fetch(RemoteContentRequest request)
> > > +      throws GadgetException;
> > >  }
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -21,6 +21,7 @@
> > >
> > >  import java.io.ByteArrayInputStream;
> > >  import java.io.InputStream;
> > > +import java.io.UnsupportedEncodingException;
> > >  import java.net.URI;
> > >  import java.util.ArrayList;
> > >  import java.util.Arrays;
> > > @@ -33,9 +34,6 @@
> > >   * Holds request data for passing to a RemoteContentFetcher.
> > >   * Instances of this object are immutable.
> > >   *
> > > - * TODO: We should probably just stick the method in here. Having
> > separate
> > > - * calls for POST vs. get seems unnecessary.
> > > - *
> > >   * TODO: This naming seems really ridiculous now. Why don't we just
> > call it
> > >   * what it is -- an HTTP request?
> > >   */
> > > @@ -50,6 +48,19 @@
> > >    }
> > >
> > >    /**
> > > +   * @return The post body as a string, assuming UTF-8 encoding.
> > > +   * TODO: We should probably tolerate other encodings, based on the
> > > +   *     Content-Type header.
> > > +   */
> > > +  public String getPostBodyAsString() {
> > > +    try {
> > > +      return new String(postBody, "UTF-8");
> > > +    } catch (UnsupportedEncodingException e) {
> > > +      return "";
> > > +    }
> > > +  }
> > > +
> > > +  /**
> > >     * Retrieves the total length of the post body.
> > >     *
> > >     * @return The length of the post body.
> > > @@ -121,6 +132,18 @@
> > >    }
> > >
> > >    /**
> > > +   * Creates a simple GET request
> > > +   *
> > > +   * @param uri
> > > +   * @param ignoreCache
> > > +   */
> > > +  public static RemoteContentRequest getRequest(URI uri, boolean
> > ignoreCache) {
> > > +    Options options = new Options();
> > > +    options.ignoreCache = ignoreCache;
> > > +    return new RemoteContentRequest(uri, options);
> > > +  }
> > > +
> > > +  /**
> > >     *
> > >     * @param method
> > >     * @param uri
> > > @@ -165,6 +188,22 @@
> > >    }
> > >
> > >    /**
> > > +   * Creates a new request to a different URL using all request data
> > from
> > > +   * an existing request.
> > > +   *
> > > +   * @param uri
> > > +   * @param base The base request to copy data from.
> > > +   */
> > > +  public RemoteContentRequest(URI uri, RemoteContentRequest base) {
> > > +    this.uri = uri;
> > > +    this.method = base.method;
> > > +    this.options = base.options;
> > > +    this.headers = base.headers;
> > > +    this.contentType = base.contentType;
> > > +    this.postBody = base.postBody;
> > > +  }
> > > +
> > > +  /**
> > >     * Basic GET request.
> > >     *
> > >     * @param uri
> > > @@ -285,6 +324,10 @@
> > >    }
> > >
> > >    public static final Options DEFAULT_OPTIONS = new Options();
> > > +  public static final Options IGNORE_CACHE_OPTIONS = new Options();
> > > +  static {
> > > +    IGNORE_CACHE_OPTIONS.ignoreCache = true;
> > > +  }
> > >
> > >    /**
> > >     * Bag of options for making a request.
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RenderingContext.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RenderingContext.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RenderingContext.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RenderingContext.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -18,6 +18,15 @@
> > >  package org.apache.shindig.gadgets;
> > >
> > >  public enum RenderingContext {
> > > +  // Used when rendering gadgets (iframes or inline).
> > > +  // TODO: rename this to "RENDER_GADGET"?
> > >    GADGET,
> > > -  CONTAINER
> > > +
> > > +  // Used when rendering container data (not a gadget render)
> > > +  CONTAINER,
> > > +
> > > +  // Used when retrieving metadata about a gadget. Processing is
> > generally
> > > +  // identical to processing under GADGET, but some operations may be
> > safely
> > > +  // skipped, such as preload processing.
> > > +  METADATA
> > >  }
> > >
> > > Added:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcher.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcher.java?rev=644123&view=auto
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcher.java
> > (added)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcher.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -0,0 +1,284 @@
> > > +/*
> > > + * Licensed under the Apache License, Version 2.0 (the "License");
> > > + * you may not use this file except in compliance with the License.
> > > + * You may obtain a copy of the License at
> > > + *
> > > + *     http://www.apache.org/licenses/LICENSE-2.0
> > > + *
> > > + * Unless required by applicable law or agreed to in writing, software
> > > + * distributed under the License is distributed on an "AS IS" BASIS,
> > > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> > implied.
> > > + * See the License for the specific language governing permissions and
> > > + * limitations under the License.
> > > + */
> > > +
> > > +package org.apache.shindig.gadgets;
> > > +
> > > +import org.apache.shindig.util.Crypto;
> > > +import org.apache.shindig.util.TimeSource;
> > > +
> > > +import net.oauth.OAuth;
> > > +import net.oauth.OAuthAccessor;
> > > +import net.oauth.OAuthConsumer;
> > > +import net.oauth.OAuthMessage;
> > > +import net.oauth.OAuth.Parameter;
> > > +import net.oauth.signature.RSA_SHA1;
> > > +
> > > +import java.net.URI;
> > > +import java.net.URISyntaxException;
> > > +import java.net.URL;
> > > +import java.security.PrivateKey;
> > > +import java.util.ArrayList;
> > > +import java.util.HashSet;
> > > +import java.util.List;
> > > +import java.util.Map;
> > > +import java.util.regex.Pattern;
> > > +
> > > +/**
> > > + * Implements signed fetch based on the OAuth request signing
> > algorithm.
> > > + *
> > > + * Subclasses can override signMessage to use their own crypto if they
> > don't
> > > + * like the oauth.net code for some reason.
> > > + *
> > > + * Instances of this class are only accessed by a single thread at a
> > time,
> > > + * but instances may be created by multiple threads.
> > > + */
> > > +public class SigningFetcher extends RemoteContentFetcher {
> > > +
> > > +  protected static final String OPENSOCIAL_OWNERID =
> > "opensocial_owner_id";
> > > +
> > > +  protected static final String OPENSOCIAL_VIEWERID =
> > "opensocial_viewer_id";
> > > +
> > > +  protected static final String OPENSOCIAL_APPID = "opensocial_app_id";
> > > +
> > > +  protected static final String XOAUTH_PUBLIC_KEY
> > > +      = "xoauth_signature_publickey";
> > > +
> > > +  protected static final Pattern ALLOWED_PARAM_NAME = Pattern
> > > +      .compile("[\\w_\\-]+");
> > > +
> > > +  protected final TimeSource clock = new TimeSource();
> > > +
> > > +  /**
> > > +   * Authentication token for the user and gadget making the request.
> > > +   */
> > > +  protected final GadgetToken authToken;
> > > +
> > > +  /**
> > > +   * Private key we pass to the OAuth RSA_SHA1 algorithm.  This can be
> > a
> > > +   * PrivateKey object, or a PEM formatted private key, or a DER
> > encoded byte
> > > +   * array for the private key.  (No, really, they accept any of them.)
> > > +   */
> > > +  protected final Object privateKeyObject;
> > > +
> > > +  /**
> > > +   * The name of the key, included in the fetch to help with key
> > rotation.
> > > +   */
> > > +  protected final String keyName;
> > > +
> > > +  /**
> > > +   * Constructor for subclasses that don't want this code to use their
> > > +   * keys.
> > > +   */
> > > +  protected SigningFetcher(RemoteContentFetcher next, GadgetToken
> > authToken) {
> > > +    this(next, authToken, null, null);
> > > +  }
> > > +
> > > +  /**
> > > +   * Constructor based on signing with the given PrivateKey object.
> > > +   *
> > > +   * @param authToken verified gadget security token
> > > +   * @param keyName name of the key to include in the request
> > > +   * @param privateKey the key to use for the signing
> > > +   */
> > > +  public static SigningFetcher makeFromPrivateKey(RemoteContentFetcher
> > next,
> > > +      GadgetToken authToken, String keyName, PrivateKey privateKey) {
> > > +    return new SigningFetcher(next, authToken, keyName, privateKey);
> > > +  }
> > > +
> > > +  /**
> > > +   * Constructor based on signing with the given PrivateKey object.
> > > +   *
> > > +   * @param authToken verified gadget security token
> > > +   * @param keyName name of the key to include in the request
> > > +   * @param privateKey base64 encoded private key
> > > +   */
> > > +  public static SigningFetcher
> > makeFromB64PrivateKey(RemoteContentFetcher next,
> > > +      GadgetToken authToken, String keyName, String privateKey) {
> > > +    return new SigningFetcher(next, authToken, keyName, privateKey);
> > > +  }
> > > +
> > > +  /**
> > > +   * Constructor based on signing with the given PrivateKey object.
> > > +   *
> > > +   * @param authToken verified gadget security token
> > > +   * @param keyName name of the key to include in the request
> > > +   * @param privateKey DER encoded private key
> > > +   */
> > > +  public static SigningFetcher makeFromPrivateKeyBytes(
> > > +      RemoteContentFetcher next, GadgetToken authToken, String keyName,
> > > +      byte[] privateKey) {
> > > +    return new SigningFetcher(next, authToken, keyName, privateKey);
> > > +  }
> > > +
> > > +  protected SigningFetcher(RemoteContentFetcher next, GadgetToken
> > authToken,
> > > +      String keyName, Object privateKeyObject) {
> > > +    super(next);
> > > +    this.authToken = authToken;
> > > +    this.keyName = keyName;
> > > +    this.privateKeyObject = privateKeyObject;
> > > +  }
> > > +
> > > +  @Override
> > > +  public RemoteContent fetch(RemoteContentRequest request)
> > > +      throws GadgetException {
> > > +    RemoteContentRequest signed = signRequest(request);
> > > +    return nextFetcher.fetch(signed);
> > > +  }
> > > +
> > > +  private RemoteContentRequest signRequest(RemoteContentRequest req)
> > > +      throws GadgetException {
> > > +    try {
> > > +      // Parse the request into parameters for OAuth signing, stripping
> > out
> > > +      // any OAuth or OpenSocial parameters injected by the client
> > > +      URI resource = req.getUri();
> > > +      String query = resource.getRawQuery();
> > > +      resource = removeQuery(resource);
> > > +      List<OAuth.Parameter> queryParams =
> > sanitize(OAuth.decodeForm(query));
> > > +      String postStr = req.getPostBodyAsString();
> > > +      List<OAuth.Parameter> postParams =
> > sanitize(OAuth.decodeForm(postStr));
> > > +      List<OAuth.Parameter> msgParams = new
> > ArrayList<OAuth.Parameter>();
> > > +      msgParams.addAll(queryParams);
> > > +      msgParams.addAll(postParams);
> > > +
> > > +      addOpenSocialParams(msgParams);
> > > +
> > > +      addOAuthParams(msgParams);
> > > +
> > > +      // Build and sign the OAuthMessage; note that the resource here
> > has
> > > +      // no query string, the parameters are all in msgParams
> > > +      OAuthMessage message
> > > +          = new OAuthMessage(req.getMethod(), resource.toString(),
> > msgParams);
> > > +
> > > +      // Sign the message, this may jump into a subclass
> > > +      signMessage(message);
> > > +
> > > +      // Rebuild the query string, including all of the parameters we
> > added.
> > > +      // We have to be careful not to copy POST parameters into the
> > query.
> > > +      // If post and query parameters share a name, they end up being
> > removed
> > > +      // from the query.
> > > +      HashSet<String> forPost = new HashSet<String>();
> > > +      for (OAuth.Parameter param : postParams) {
> > > +        forPost.add(param.getKey());
> > > +      }
> > > +      List<Map.Entry<String, String>> newQuery =
> > > +        new ArrayList<Map.Entry<String, String>>();
> > > +      for (Map.Entry<String, String> param : message.getParameters()) {
> > > +        if (! forPost.contains(param.getKey())) {
> > > +          newQuery.add(param);
> > > +        }
> > > +      }
> > > +      // Careful here; the OAuth form encoding scheme is slightly
> > different than
> > > +      // the normal form encoding scheme, so we have to use the OAuth
> > library
> > > +      // formEncode method.  The java.net.URI code makes it difficult
> > to insert
> > > +      // a pre-encoded query string, so we use URL instead.
> > > +      String finalQuery = OAuth.formEncode(newQuery);
> > > +      URL url = new URL(
> > > +          resource.getScheme(),
> > > +          resource.getHost(),
> > > +          resource.getPort(),
> > > +          resource.getRawPath() + "?" + finalQuery);
> > > +      return new RemoteContentRequest(url.toURI(), req);
> > > +    } catch (Exception e) {
> > > +      throw new
> > GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
> > > +    }
> > > +  }
> > > +
> > > +  private URI removeQuery(URI resource) throws URISyntaxException {
> > > +    return new URI(
> > > +        resource.getScheme(),
> > > +        null, // user info
> > > +        resource.getHost(),
> > > +        resource.getPort(),
> > > +        resource.getRawPath(),
> > > +        null, // query
> > > +        null); // fragment
> > > +  }
> > > +
> > > +
> > > +  private void addOpenSocialParams(List<Parameter> msgParams) {
> > > +    String owner = authToken.getOwnerId();
> > > +    if (owner != null) {
> > > +      msgParams.add(new OAuth.Parameter(OPENSOCIAL_OWNERID, owner));
> > > +    }
> > > +
> > > +    String viewer = authToken.getViewerId();
> > > +    if (viewer != null) {
> > > +      msgParams.add(new OAuth.Parameter(OPENSOCIAL_VIEWERID, viewer));
> > > +    }
> > > +
> > > +    String app = authToken.getAppId();
> > > +    if (app != null) {
> > > +      msgParams.add(new OAuth.Parameter(OPENSOCIAL_APPID, app));
> > > +    }
> > > +
> > > +  }
> > > +
> > > +  private void addOAuthParams(List<Parameter> msgParams) {
> > > +    msgParams.add(new OAuth.Parameter(OAuth.OAUTH_TOKEN, ""));
> > > +
> > > +    String domain = authToken.getDomain();
> > > +    if (domain != null) {
> > > +      msgParams.add(new OAuth.Parameter(OAuth.OAUTH_CONSUMER_KEY,
> > domain));
> > > +    }
> > > +
> > > +    if (keyName != null) {
> > > +      msgParams.add(new OAuth.Parameter(XOAUTH_PUBLIC_KEY, keyName));
> > > +    }
> > > +
> > > +    String nonce = Long.toHexString(Crypto.rand.nextLong());
> > > +    msgParams.add(new OAuth.Parameter(OAuth.OAUTH_NONCE, nonce));
> > > +
> > > +    String timestamp = Long.toString(clock.currentTimeMillis()/1000L);
> > > +    msgParams.add(new OAuth.Parameter(OAuth.OAUTH_TIMESTAMP,
> > timestamp));
> > > +
> > > +    msgParams.add(new OAuth.Parameter(OAuth.OAUTH_SIGNATURE_METHOD,
> > > +        OAuth.RSA_SHA1));
> > > +  }
> > > +
> > > +  /**
> > > +   * Sign a message and append the oauth signature parameter to the
> > message
> > > +   * object.
> > > +   *
> > > +   * @param message the message to sign
> > > +   *
> > > +   * @throws Exception because the OAuth libraries require it.
> > > +   */
> > > +  protected void signMessage(OAuthMessage message) throws Exception {
> > > +    OAuthConsumer consumer = new OAuthConsumer(null, null, null, null);
> > > +    consumer.setProperty(RSA_SHA1.PRIVATE_KEY, privateKeyObject);
> > > +    OAuthAccessor accessor = new OAuthAccessor(consumer);
> > > +    message.sign(accessor);
> > > +  }
> > > +
> > > +  /**
> > > +   * Strip out any owner or viewer id passed by the client.
> > > +   */
> > > +  private List<Parameter> sanitize(List<Parameter> params) {
> > > +    ArrayList<Parameter> list = new ArrayList<Parameter>();
> > > +    for (Parameter p : params) {
> > > +      if (allowParam(p.getKey())) {
> > > +        list.add(p);
> > > +      }
> > > +    }
> > > +    return list;
> > > +  }
> > > +
> > > +  private boolean allowParam(String paramName) {
> > > +    String canonParamName = paramName.toLowerCase();
> > > +    return (!(canonParamName.startsWith("oauth") ||
> > > +        canonParamName.startsWith("xoauth") ||
> > > +        canonParamName.startsWith("opensocial")) &&
> > > +        ALLOWED_PARAM_NAME.matcher(canonParamName).matches());
> > > +  }
> > > +}
> > >
> > > Added:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcherFactory.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcherFactory.java?rev=644123&view=auto
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcherFactory.java
> > (added)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcherFactory.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -0,0 +1,71 @@
> > > +/*
> > > + * 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;
> > > +
> > > +import org.apache.shindig.util.InputStreamConsumer;
> > > +import org.apache.shindig.util.ResourceLoader;
> > > +
> > > +import com.google.inject.Inject;
> > > +import com.google.inject.name.Named;
> > > +
> > > +import java.io.IOException;
> > > +
> > > +/**
> > > + * Produces Signing content fetchers for input tokens.
> > > + */
> > > +public class SigningFetcherFactory {
> > > +  private final String keyName;
> > > +  private final String privateKey;
> > > +
> > > +  /**
> > > +   * Produces a signing fetcher that will sign requests and delegate
> > actual
> > > +   * network retrieval to the {@code networkFetcher}
> > > +   *
> > > +   * @param networkFetcher The fetcher that will be doing actual work.
> > > +   * @param token The gadget token used for extracting signing
> > parameters.
> > > +   * @return The signing fetcher.
> > > +   */
> > > +  public RemoteContentFetcher getSigningFetcher(
> > > +      RemoteContentFetcher networkFetcher, GadgetToken token) {
> > > +    return SigningFetcher.makeFromB64PrivateKey(
> > > +        networkFetcher, token, keyName, privateKey);
> > > +  }
> > > +
> > > +  /**
> > > +   * @param keyName The key name (may be null) used in the signature.
> > > +   * @param keyFile The file containing your private key for signing
> > requests.
> > > +   */
> > > +  @Inject
> > > +  public SigningFetcherFactory(@Named("signing.key-name") String
> > keyName,
> > > +                               @Named("signing.key-file") String
> > keyFile) {
> > > +    if (keyName == null || keyName.length() == 0) {
> > > +      this.keyName = null;
> > > +    } else {
> > > +      this.keyName = keyName;
> > > +    }
> > > +    String privateKey = null;
> > > +    try {
> > > +      privateKey
> > > +          =
> > InputStreamConsumer.readToString(ResourceLoader.open(keyFile));
> > > +    } catch (IOException e) {
> > > +      privateKey = "";
> > > +    }
> > > +    this.privateKey = privateKey;
> > > +  }
> > > +}
> > >
> > > Modified:
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SyndicatorConfig.java
> > > URL:
> > http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SyndicatorConfig.java?rev=644123&r1=644122&r2=644123&view=diff
> > >
> > ==============================================================================
> > > ---
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SyndicatorConfig.java
> > (original)
> > > +++
> > incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SyndicatorConfig.java
> > Wed Apr  2 17:40:05 2008
> > > @@ -21,6 +21,9 @@
> > >
> > >  import org.apache.shindig.util.ResourceLoader;
> > >
> > > +import com.google.inject.Inject;
> > > +import com.google.inject.name.Named;
> > > +
> > >  import org.json.JSONArray;
> > >  import org.json.JSONException;
> > >  import org.json.JSONObject;
> > > @@ -45,7 +48,6 @@
> > >   * your config that you actually want to change.
> > >   */
> > >  public class SyndicatorConfig {
> > > -  public static final SyndicatorConfig EMPTY = new SyndicatorConfig();
> > >    private final Map<String, JSONObject> config;
> > >    public static final String DEFAULT_SYNDICATOR = "default";
> > >    public static final String SYNDICATOR_KEY = "gadgets.syndicator";
> > > @@ -168,6 +170,7 @@
> > >    private void loadResources(String[] files)  throws GadgetException {
> > >      try {
> > >        for (String entry : files) {
> > > +        logger.info("Reading syndicator config: " + entry);
> > >          String content = ResourceLoader.getContent(entry);
> > >          loadFromString(content);
> > >        }
> > > @@ -212,8 +215,9 @@
> > >      for (String field : fields) {
> > >        Object existing = clone.opt(field);
> > >        Object update = merge.get(field);
> > > -      if (existing == null) {
> > > -        // It's new custom config, not referenced in the prototype.
> > > +      if (existing == null || update == null) {
> > > +        // It's new custom config, not referenced in the prototype, or
> > > +        // it's removing a pre-configured value.
> > >          clone.put(field, update);
> > >        } else {
> > >          // Merge if object type is JSONObject.
> > > @@ -290,20 +294,13 @@
> > >
> > >    /**
> > >     * Creates a new, empty configuration.
> > > -   *
> > > -   * @param defaultSyndicator The default syndicators to load.
> > >     */
> > > -  public SyndicatorConfig(String defaultSyndicator) throws
> > GadgetException {
> > > +  @Inject
> > > +  public SyndicatorConfig(@Named("syndicators.default") String
> > syndicators)
> > > +      throws GadgetException {
> > >      config = new HashMap<String, JSONObject>();
> > > -    if (defaultSyndicator != null) {
> > > -      loadSyndicators(defaultSyndicator);
> > > +    if (syndicators != null) {
> > > +      loadSyndicators(syndicators);
> > >      }
> > > -  }
> > > -
> > > -  /**
> > > -   * Creates an unmodifiable configuration.
> > > -   */
> > > -  private SyndicatorConfig() {
> > > -    config = Collections.emptyMap();
> > >    }
> > >  }
> > >
> > >
> > --
> > Santiago Gala
> > http://memojo.com/~sgala/blog/ <http://memojo.com/%7Esgala/blog/>
> >
> >
> 
> 
-- 
Santiago Gala
http://memojo.com/~sgala/blog/