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/03 20:23:09 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/java/or...

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/