You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by John Hjelmstad <fa...@google.com> on 2008/10/18 01:33:25 UTC

Re: svn commit: r705780 - in /incubator/shindig/trunk: ./ java/common/src/main/java/org/apache/shindig/auth/ java/common/src/main/java/org/apache/shindig/common/xml/ java/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/ java/gadgets/sr

Given that Neko is demonstrably faster, and if I understand your results,
equally lenient w/ input (if not better), I'd vote to enable it by default.
We haven't even made the parse-based rewriter the default yet -- Neko gets
us close to, or arrived at, being able to do so.
--John

On Fri, Oct 17, 2008 at 4:28 PM, <lr...@apache.org> wrote:

> Author: lryan
> Date: Fri Oct 17 16:28:33 2008
> New Revision: 705780
>
> URL: http://svn.apache.org/viewvc?rev=705780&view=rev
> Log:
> Add support for the Nekohtml parser to the HTML parsing and rewriter infra
> Neko is not enabled by default. To enable it see ParseModule
> To compare Caja and Neko use ParseTreeSerializerBenchmark
>
> Added:
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParseModule.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/cajatest.html
>
>  incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/HtmlParserTest.java
>      - copied, changed from r704682,
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParserTest.java
>
>  incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/ParseTreeSerializerBenchmark.java
>      - copied, changed from r704682,
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/ParseTreeSerializerTest.java
> Removed:
>
>  incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/ParseTreeSerializerTest.java
>
>  incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParserTest.java
> Modified:
>
>  incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AuthenticationHandler.java
>
>  incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AuthenticationServletFilter.java
>
>  incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/UrlParameterAuthenticationHandler.java
>
>  incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/xml/XmlUtil.java
>    incubator/shindig/trunk/java/gadgets/pom.xml
>
>  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/parse/AbstractCachingGadgetHtmlParser.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
>
>  incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java
>
>  incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/MutableContentTest.java
>
>  incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/oauth/OAuthConsumerRequestAuthenticationHandler.java
>
>  incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthLookupService.java
>
>  incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleContainerOAuthLookupService.java
>    incubator/shindig/trunk/pom.xml
>
> Modified:
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AuthenticationHandler.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AuthenticationHandler.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AuthenticationHandler.java
> (original)
> +++
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AuthenticationHandler.java
> Fri Oct 17 16:28:33 2008
> @@ -17,6 +17,8 @@
>  */
>  package org.apache.shindig.auth;
>
> +import java.util.Map;
> +
>  import javax.servlet.http.HttpServletRequest;
>
>  /**
> @@ -37,4 +39,43 @@
>    * @return A valid security token for the request, or null if it wasn't
> possible to authenticate.
>    */
>   SecurityToken getSecurityTokenFromRequest(HttpServletRequest request);
> +
> +  /**
> +   * An exception thrown by an AuthenticationHandler in the situation
> where
> +   * a malformed credential or token is passed. A handler which throws
> this exception
> +   * is required to include the appropriate error state in the servlet
> response
> +   */
> +  public static final class InvalidAuthenticationException extends
> RuntimeException {
> +
> +    private Map<String,String> additionalHeaders;
> +    private String redirect;
> +
> +    /**
> +     * @param message Message to output in error response
> +     * @param cause Underlying exception
> +     */
> +    public InvalidAuthenticationException(String message, Throwable cause)
> {
> +      this(message, cause, null, null);
> +    }
> +
> +    /**
> +     * @param message Message to output in error response
> +     * @param additionalHeaders Headers to add to error response
> +     * @param cause Underlying exception
> +     */
> +    public InvalidAuthenticationException(String message, Throwable cause,
> +        Map<String,String> additionalHeaders, String redirect) {
> +      super(message, cause);
> +      this.additionalHeaders = additionalHeaders;
> +      this.redirect = redirect;
> +    }
> +
> +    public Map<String, String> getAdditionalHeaders() {
> +      return additionalHeaders;
> +    }
> +
> +    public String getRedirect() {
> +      return redirect;
> +    }
> +  }
>  }
>
> Modified:
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AuthenticationServletFilter.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AuthenticationServletFilter.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AuthenticationServletFilter.java
> (original)
> +++
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AuthenticationServletFilter.java
> Fri Oct 17 16:28:33 2008
> @@ -23,12 +23,16 @@
>
>  import java.io.IOException;
>  import java.util.List;
> +import java.util.Map;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
>
>  import javax.servlet.FilterChain;
>  import javax.servlet.ServletException;
>  import javax.servlet.ServletRequest;
>  import javax.servlet.ServletResponse;
>  import javax.servlet.http.HttpServletRequest;
> +import javax.servlet.http.HttpServletResponse;
>
>  /**
>  * Filter that attempts to authenticate an incoming HTTP request. It uses
> the guice injected
> @@ -43,6 +47,9 @@
>
>   private List<AuthenticationHandler> handlers;
>
> +  private static final Logger logger = Logger.getLogger(
> +      AuthenticationServletFilter.class.getName());
> +
>   @Inject
>   public void setAuthenticationHandlers(List<AuthenticationHandler>
> handlers) {
>     this.handlers = handlers;
> @@ -58,17 +65,31 @@
>     }
>
>     HttpServletRequest req = (HttpServletRequest) request;
> +    HttpServletResponse resp = (HttpServletResponse) response;
>
> -    for (AuthenticationHandler handler : handlers) {
> -      SecurityToken token = handler.getSecurityTokenFromRequest(req);
> -      if (token != null) {
> -        new
> AuthInfo(req).setAuthType(handler.getName()).setSecurityToken(token);
> -        chain.doFilter(req, response);
> -        return;
> +    try {
> +      for (AuthenticationHandler handler : handlers) {
> +        SecurityToken token = handler.getSecurityTokenFromRequest(req);
> +        if (token != null) {
> +          new
> AuthInfo(req).setAuthType(handler.getName()).setSecurityToken(token);
> +          chain.doFilter(req, response);
> +          return;
> +        }
> +      }
> +      // We did not find a security token so we will just pass null
> +      chain.doFilter(req, response);
> +    } catch (AuthenticationHandler.InvalidAuthenticationException iae) {
> +      logger.log(Level.INFO, iae.getMessage(), iae.getCause());
> +      if (iae.getAdditionalHeaders() != null) {
> +        for (Map.Entry<String,String> entry :
> iae.getAdditionalHeaders().entrySet()) {
> +          resp.addHeader(entry.getKey(), entry.getValue());
> +        }
> +      }
> +      if (iae.getRedirect() != null) {
> +        resp.sendRedirect(iae.getRedirect());
> +      } else {
> +        resp.sendError(HttpServletResponse.SC_UNAUTHORIZED,
> iae.getMessage());
>       }
>     }
> -
> -    // We did not find a security token so we will just pass null
> -    chain.doFilter(req, response);
>   }
>  }
>
> Modified:
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/UrlParameterAuthenticationHandler.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/UrlParameterAuthenticationHandler.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/UrlParameterAuthenticationHandler.java
> (original)
> +++
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/UrlParameterAuthenticationHandler.java
> Fri Oct 17 16:28:33 2008
> @@ -21,8 +21,6 @@
>
>  import java.util.Collections;
>  import java.util.Map;
> -import java.util.logging.Level;
> -import java.util.logging.Logger;
>
>  import javax.servlet.http.HttpServletRequest;
>
> @@ -32,9 +30,6 @@
>  public class UrlParameterAuthenticationHandler implements
> AuthenticationHandler {
>   public static final String AUTH_URL_PARAMETER =
> "SecurityTokenUrlParameter";
>
> -  private static final Logger logger = Logger.getLogger(
> -      UrlParameterAuthenticationHandler.class.getName());
> -
>   private final SecurityTokenDecoder securityTokenDecoder;
>
>   @Inject
> @@ -47,14 +42,17 @@
>   }
>
>   public SecurityToken getSecurityTokenFromRequest(HttpServletRequest
> request) {
> +    String token = request.getParameter("st");
> +    // Not token provided, try an alternate auth method
> +    if (token == null) {
> +      return null;
> +    }
>     try {
> -      String token = request.getParameter("st");
>       Map<String, String> parameters
>           =
> Collections.singletonMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, token);
>       return securityTokenDecoder.createToken(parameters);
>     } catch (SecurityTokenException e) {
> -      logger.log(Level.INFO, "Valid security token not found.", e);
> -      return null;
> +      throw new InvalidAuthenticationException("Malformed security token "
> + token, e);
>     }
>   }
>  }
>
> Modified:
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/xml/XmlUtil.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/xml/XmlUtil.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/xml/XmlUtil.java
> (original)
> +++
> incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/xml/XmlUtil.java
> Fri Oct 17 16:28:33 2008
> @@ -15,7 +15,6 @@
>  * KIND, either express or implied. See the License for the
>  * specific language governing permissions and limitations under the
> License.
>  */
> -
>  package org.apache.shindig.common.xml;
>
>  import org.apache.shindig.common.uri.Uri;
> @@ -249,6 +248,20 @@
>     return getIntAttribute(node, attr, 0);
>   }
>
> +  /**
> +   * @return first child node matching the specified name
> +   */
> +  public static Node getFirstNamedChildNode(Node root, String nodeName) {
> +    Node current = root.getFirstChild();
> +    while (current != null) {
> +      if (current.getNodeName().equalsIgnoreCase(nodeName)) {
> +        return current;
> +      }
> +      current = current.getNextSibling();
> +    }
> +    return null;
> +  }
> +
>   /**
>    * Fetch a builder from the pool, creating a new one only if necessary.
>    */
> @@ -282,6 +295,8 @@
>     }
>   }
>
> +
> +
>   /**
>    * Attempts to parse the input xml into a single element.
>    * @param xml
>
> Modified: incubator/shindig/trunk/java/gadgets/pom.xml
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/pom.xml?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> --- incubator/shindig/trunk/java/gadgets/pom.xml (original)
> +++ incubator/shindig/trunk/java/gadgets/pom.xml Fri Oct 17 16:28:33 2008
> @@ -157,5 +157,17 @@
>       <artifactId>icu4j</artifactId>
>       <scope>compile</scope>
>     </dependency>
> +    <dependency>
> +      <groupId>net.sourceforge.nekohtml</groupId>
> +      <artifactId>nekohtml</artifactId>
> +    </dependency>
> +    <dependency>
> +      <groupId>net.sourceforge.nekohtml</groupId>
> +      <artifactId>nekohtml</artifactId>
> +    </dependency>
> +    <dependency>
> +      <groupId>xerces</groupId>
> +      <artifactId>xercesImpl</artifactId>
> +    </dependency>
>   </dependencies>
>  </project>
>
> Modified:
> 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=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java
> Fri Oct 17 16:28:33 2008
> @@ -25,6 +25,7 @@
>  import org.apache.shindig.gadgets.rewrite.ContentRewriter;
>  import org.apache.shindig.gadgets.rewrite.lexer.DefaultContentRewriter;
>  import org.apache.shindig.gadgets.servlet.CajaContentRewriter;
> +import org.apache.shindig.gadgets.parse.ParseModule;
>
>  import com.google.common.collect.Lists;
>  import com.google.inject.AbstractModule;
> @@ -50,6 +51,8 @@
>     bind(Executor.class).toInstance(service);
>     bind(ExecutorService.class).toInstance(service);
>
> +    this.install(new ParseModule());
> +
>     bind(new
> TypeLiteral<List<ContentRewriter>>(){}).toProvider(ContentRewritersProvider.class);
>     bind(new
> TypeLiteral<List<Preloader>>(){}).toProvider(PreloaderProvider.class);
>
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/AbstractCachingGadgetHtmlParser.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/AbstractCachingGadgetHtmlParser.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/AbstractCachingGadgetHtmlParser.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/AbstractCachingGadgetHtmlParser.java
> Fri Oct 17 16:28:33 2008
> @@ -35,7 +35,7 @@
>  * Essentially any real {@code GadgetHtmlParser} should extend this base
> class, as
>  * its abstract method's signature is identical to the interface.
>  */
> -public abstract class AbstractCachingGadgetHtmlParser implements
> GadgetHtmlParser {
> +public abstract class AbstractCachingGadgetHtmlParser extends
> GadgetHtmlParser {
>   protected abstract List<ParsedHtmlNode> doParse(String source) throws
> GadgetException;
>
>   private final Cache<String, byte[]> parseTreeCache;
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
> Fri Oct 17 16:28:33 2008
> @@ -17,12 +17,13 @@
>  */
>  package org.apache.shindig.gadgets.parse;
>
> -import com.google.inject.ImplementedBy;
> -
>  import org.apache.shindig.gadgets.GadgetException;
>  import org.apache.shindig.gadgets.parse.caja.CajaHtmlParser;
>
> -import java.util.List;
> +import com.google.inject.ImplementedBy;
> +
> +import org.w3c.dom.Node;
> +import org.w3c.dom.Document;
>
>  /**
>  * Parser for arbitrary HTML content. The content may simply be a
> @@ -33,6 +34,23 @@
>  * {@see ParsedHtmlNode} for parsing details
>  */
>  @ImplementedBy(CajaHtmlParser.class)
> -public interface GadgetHtmlParser {
> -  public List<ParsedHtmlNode> parse(String source) throws GadgetException;
> +public abstract class GadgetHtmlParser {
> +
> +  /**
> +   * @param content
> +   * @return true if we detect a preamble of doctype or html
> +   */
> +  protected static boolean attemptFullDocParseFirst(String content) {
> +    String normalized = content.substring(Math.min(100,
> content.length())).toUpperCase();
> +    return normalized.contains("<!DOCTYPE") ||
> normalized.contains("<HTML");
> +  }
> +
> +  public abstract java.util.List<ParsedHtmlNode> parse(String source)
> throws GadgetException;
> +
> +  /**
> +   * @param source
> +   * @return a parsed document or document fragment
> +   * @throws GadgetException
> +   */
> +  public abstract Document parseDom(String source) throws GadgetException;
>  }
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParseModule.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParseModule.java?rev=705780&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParseModule.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/ParseModule.java
> Fri Oct 17 16:28:33 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.parse;
> +
> +import org.apache.shindig.gadgets.parse.caja.CajaHtmlParser;
> +
> +import com.google.inject.AbstractModule;
> +import com.google.inject.Provider;
> +
> +import org.w3c.dom.html.HTMLDocument;
> +
> +/**
> + * Provide parse bindings
> + */
> +public class ParseModule extends AbstractModule {
> +
> +  /**
> +   * {@InheritDoc}
> +   */
> +  @Override
> +  protected void configure() {
> +    //bind(GadgetHtmlParser.class).to(NekoHtmlParser.class);
> +    bind(GadgetHtmlParser.class).to(CajaHtmlParser.class);
> +    bind(HTMLDocument.class).toProvider(HTMLDocumentProvider.class);
> +  }
> +
> +  /**
> +   * Provider of new HTMLDocument implementations. Used to hide XML parser
> weirdness
> +   */
> +  public static class HTMLDocumentProvider implements
> Provider<HTMLDocument> {
> +
> +    Class htmlDocImpl;
> +
> +    public HTMLDocumentProvider() {
> +      // This is ugly but effective
> +      try {
> +        htmlDocImpl =
> Class.forName("org.apache.html.dom.HTMLDocumentImpl");
> +      } catch (ClassNotFoundException cnfe) {
> +        try {
> +          htmlDocImpl =
> Class.forName("com.sun.org.apache.html.internal.dom.HTMLDocumentImpl");
> +        } catch (ClassNotFoundException cnfe2) {
> +          throw new RuntimeException("Could not find HTML DOM
> implementation", cnfe2);
> +        }
> +      }
> +    }
> +
> +    public HTMLDocument get() {
> +      try {
> +        return (HTMLDocument) htmlDocImpl.newInstance();
> +      } catch (Exception e) {
> +        throw new RuntimeException("Could not create HTML DOM from class "
> +            + htmlDocImpl.getName(), e);
> +      }
> +    }
> +  }
> +}
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java
> Fri Oct 17 16:28:33 2008
> @@ -17,6 +17,11 @@
>  */
>  package org.apache.shindig.gadgets.parse.caja;
>
> +import org.apache.shindig.gadgets.GadgetException;
> +import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
> +import org.apache.shindig.gadgets.parse.ParsedHtmlAttribute;
> +import org.apache.shindig.gadgets.parse.ParsedHtmlNode;
> +
>  import com.google.caja.lexer.CharProducer;
>  import com.google.caja.lexer.HtmlLexer;
>  import com.google.caja.lexer.HtmlTokenType;
> @@ -27,12 +32,15 @@
>  import com.google.caja.parser.html.DomTree;
>  import com.google.caja.reporting.MessageQueue;
>  import com.google.caja.reporting.SimpleMessageQueue;
> +import com.google.inject.Provider;
>  import com.google.inject.Singleton;
> +import com.google.inject.Inject;
>
> -import org.apache.shindig.gadgets.GadgetException;
> -import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
> -import org.apache.shindig.gadgets.parse.ParsedHtmlAttribute;
> -import org.apache.shindig.gadgets.parse.ParsedHtmlNode;
> +import org.w3c.dom.Attr;
> +import org.w3c.dom.Element;
> +import org.w3c.dom.Node;
> +import org.w3c.dom.Document;
> +import org.w3c.dom.html.HTMLDocument;
>
>  import java.io.StringReader;
>  import java.net.URI;
> @@ -44,20 +52,18 @@
>  * Caja-based implementation of a {@code GadgetHtmlParser}.
>  */
>  @Singleton
> -public class CajaHtmlParser implements GadgetHtmlParser {
> +public class CajaHtmlParser extends GadgetHtmlParser {
> +
> +  Provider<HTMLDocument> documentProvider;
>
> -  /** {@inheritDoc */
> +  @Inject
> +  public CajaHtmlParser(Provider<HTMLDocument> documentProvider) {
> +    this.documentProvider = documentProvider;
> +  }
> +
> +  @Override
>   public List<ParsedHtmlNode> parse(String source) throws GadgetException {
> -    // Wrap the whole thing in a top-level node to get full contents.
> -    DomParser parser = getParser("<html>" + source + "</html>");
> -
> -    DomTree domTree = null;
> -    try {
> -      domTree = parser.parseFragment();
> -    } catch (ParseException e) {
> -      throw new GadgetException(GadgetException.Code.CSS_PARSE_ERROR, e);
> -    }
> -
> +    DomTree domTree = getFragment(source);
>     List<ParsedHtmlNode> nodes =
>         new ArrayList<ParsedHtmlNode>(domTree.children().size());
>     for (DomTree child : domTree.children()) {
> @@ -65,15 +71,36 @@
>     }
>     return nodes;
>   }
> -
> -  public DomParser getParser(String content) {
> +
> +  @Override
> +  public Document parseDom(String source) throws GadgetException {
> +    // Wrap the whole thing in a top-level node to get full contents.
> +    return makeDocument(getFragment(source));
> +  }
> +
> +  DomTree.Fragment getFragment(String content) throws GadgetException {
> +    DomParser parser = getParser(content);
> +    try {
> +      return parser.parseFragment();
> +    } catch (ParseException pe) {
> +      try {
> +        // Revert to nastiness
> +        DomTree.Fragment fragment = getParser("<HTML>" + content +
> "</HTML>").parseFragment();
> +        return new
> DomTree.Fragment(fragment.children().get(0).children());
> +      } catch (ParseException pe2) {
> +        throw new GadgetException(GadgetException.Code.HTML_PARSE_ERROR,
> pe2);
> +      }
> +    }
> +  }
> +
> +  DomParser getParser(String content) {
>     InputSource source = null;
>     try {
>       source = new InputSource(new URI("http://dummy.com/"));
>     } catch (URISyntaxException e) {
>       // Never happens. Dummy URI needed to satisfy API.
>       // We may want to pass in the gadget URI for auditing
> -      // purposes at some point.
> +      // purposes at some point.
>     }
>     CharProducer producer = CharProducer.Factory.create(
>         new StringReader(content), source);
> @@ -82,6 +109,47 @@
>     return new DomParser(new TokenQueue<HtmlTokenType>(lexer, source),
> false, mQueue);
>   }
>
> +  private HTMLDocument makeDocument(DomTree.Fragment fragment) {
> +    HTMLDocument htmlDocument = documentProvider.get();
> +
> +    // Check if doc contains an HTML node. If so just add it and recurse
> +    for (DomTree node : fragment.children()) {
> +      if (node instanceof DomTree.Tag &&
> +          ((DomTree.Tag)node).getTagName().equalsIgnoreCase("HTML")) {
> +        recurseDocument(htmlDocument, htmlDocument, node);
> +        return htmlDocument;
> +      }
> +    }
> +    Node root =
> htmlDocument.appendChild(htmlDocument.createElement("HTML"));
> +    for (DomTree child : fragment.children()) {
> +      recurseDocument(htmlDocument, root, child);
> +    }
> +    return htmlDocument;
> +  }
> +
> +  private static void recurseDocument(HTMLDocument doc, Node parent,
> DomTree elem) {
> +    if (elem instanceof DomTree.Tag) {
> +      DomTree.Tag tag = (DomTree.Tag) elem;
> +      Element element = doc.createElement(tag.getTagName());
> +      parent.appendChild(element);
> +      for (DomTree child : elem.children()) {
> +        recurseDocument(doc, element, child);
> +      }
> +    } else if (elem instanceof DomTree.Attrib) {
> +      DomTree.Attrib attrib = (DomTree.Attrib) elem;
> +      Attr domAttrib = doc.createAttribute(attrib.getAttribName());
> +      parent.getAttributes().setNamedItem(domAttrib);
> +      domAttrib.setValue(attrib.getAttribValue());
> +    } else if (elem instanceof DomTree.Text) {
> +      parent.appendChild(doc.createTextNode(elem.getValue()));
> +    } else if (elem instanceof DomTree.CData) {
> +      //
> +      parent.appendChild(doc.createCDATASection(elem.getValue()));
> +    } else {
> +      // TODO Implement for comment, fragment etc...
> +    }
> +  }
> +
>   /**
>    * {@code ParsedHtmlNode} implementation built using Caja parsing
> primitives.
>    */
> @@ -94,7 +162,7 @@
>     private CajaParsedHtmlNode(DomTree elem) {
>       if (elem instanceof DomTree.Tag) {
>         DomTree.Tag tag = (DomTree.Tag)elem;
> -        attributes = new ArrayList<ParsedHtmlAttribute>();
> +        attributes = new ArrayList<ParsedHtmlAttribute>(1);
>         children = new ArrayList<ParsedHtmlNode>();
>         name = tag.getTagName();
>         text = null;
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java?rev=705780&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
> Fri Oct 17 16:28:33 2008
> @@ -0,0 +1,171 @@
> +/**
> + * 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.parse.nekohtml;
> +
> +import org.apache.shindig.common.xml.XmlUtil;
> +import org.apache.shindig.gadgets.GadgetException;
> +import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
> +import org.apache.shindig.gadgets.parse.ParsedHtmlAttribute;
> +import org.apache.shindig.gadgets.parse.ParsedHtmlNode;
> +
> +import com.google.common.collect.Lists;
> +import com.google.inject.Provider;
> +import com.google.inject.Inject;
> +
> +import org.cyberneko.html.parsers.DOMFragmentParser;
> +import org.w3c.dom.Document;
> +import org.w3c.dom.DocumentFragment;
> +import org.w3c.dom.NamedNodeMap;
> +import org.w3c.dom.Node;
> +import org.w3c.dom.NodeList;
> +import org.w3c.dom.html.HTMLDocument;
> +import org.xml.sax.InputSource;
> +import org.xml.sax.SAXException;
> +
> +import java.io.IOException;
> +import java.io.StringReader;
> +import java.util.Collections;
> +import java.util.List;
> +
> +/**
> + * Parser that uses the NekoHtml parser.
> + *
> + * TODO:
> + * Currently this code uses the ParsedXXX wrapper types so we can share
> abstraction
> + * with Caja. This is probably unnecessary overhead and we would prefer
> that Caja
> + * implements up to org.w3c.dom (or perhaps the Caja wrapper types
> should?)
> + */
> +public class NekoHtmlParser extends GadgetHtmlParser {
> +
> +  Provider<HTMLDocument> documentProvider;
> +
> +  @Inject
> +  public NekoHtmlParser(Provider<HTMLDocument> documentProvider) {
> +    this.documentProvider = documentProvider;
> +  }
> +
> +  public List<ParsedHtmlNode> parse(String source) throws GadgetException
> {
> +    try {
> +      Document doc = parseFragment(source);
> +      return unwrapNodeList(doc.getFirstChild().getChildNodes());
> +    } catch (Exception e) {
> +      throw new GadgetException(GadgetException.Code.HTML_PARSE_ERROR, e);
> +    }
> +  }
> +
> +  public Document parseDom(String source) throws GadgetException {
> +    try {
> +      return parseFragment(source);
> +    } catch (Exception e) {
> +      throw new GadgetException(GadgetException.Code.HTML_PARSE_ERROR, e);
> +    }
> +  }
> +
> +  private Document parseFragment(String source) throws SAXException,
> IOException {
> +    InputSource input = new InputSource(new StringReader(source));
> +    DOMFragmentParser parser = new DOMFragmentParser();
> +
> +    HTMLDocument htmlDoc = documentProvider.get();
> +    DocumentFragment fragment = htmlDoc.createDocumentFragment();
> +    parser.parse(input, fragment);
> +    Node htmlNode = XmlUtil.getFirstNamedChildNode(fragment, "HTML");
> +    if (htmlNode != null) {
> +      htmlDoc.appendChild(htmlNode);
> +    } else {
> +      Node root = htmlDoc.appendChild(htmlDoc.createElement("HTML"));
> +      root.appendChild(fragment);
> +    }
> +    return htmlDoc;
> +  }
> +
> +  private static List<ParsedHtmlNode> unwrapNodeList(NodeList nodeList) {
> +    if (nodeList == null) return Collections.emptyList();
> +    List<ParsedHtmlNode> list =
> Lists.newArrayListWithExpectedSize(nodeList.getLength());
> +    for (int i = 0; i < nodeList.getLength(); i++) {
> +      list.add(new NodeWrapper(nodeList.item(i)));
> +    }
> +    return list;
> +  }
> +
> +  private static List<ParsedHtmlAttribute>
> unwrapAttributeList(NamedNodeMap attrList) {
> +    if (attrList == null) return Collections.emptyList();
> +    List<ParsedHtmlAttribute> list =
> Lists.newArrayListWithExpectedSize(attrList.getLength());
> +    for (int i = 0; i < attrList.getLength(); i++) {
> +      list.add(new AttributeWrapper(attrList.item(i)));
> +    }
> +    return list;
> +  }
> +
> +  static class NodeWrapper implements ParsedHtmlNode {
> +    private Node wrapped;
> +    private List<ParsedHtmlAttribute> attributes;
> +    private List<ParsedHtmlNode> children;
> +
> +    NodeWrapper(Node wrapped) {
> +      this.wrapped = wrapped;
> +      getChildren();
> +      getAttributes();
> +    }
> +
> +    public String getTagName() {
> +      if (wrapped.getNodeType() == Node.TEXT_NODE) return null;
> +      return wrapped.getNodeName();
> +    }
> +
> +    public List<ParsedHtmlAttribute> getAttributes() {
> +      if (wrapped.getNodeType() == Node.TEXT_NODE) return null;
> +      if (attributes == null) {
> +        attributes = unwrapAttributeList(wrapped.getAttributes());
> +      }
> +      return attributes;
> +    }
> +
> +    public List<ParsedHtmlNode> getChildren() {
> +      if (wrapped.getNodeType() == Node.TEXT_NODE) return null;
> +      if (children == null) {
> +        children = unwrapNodeList(wrapped.getChildNodes());
> +      }
> +      // YUK!
> +      if (children.isEmpty()) return null;
> +      return children;
> +    }
> +
> +    public String getText() {
> +      if (wrapped.getNodeType() == Node.TEXT_NODE ) {
> +        return wrapped.getTextContent();
> +      }
> +      return null;
> +    }
> +  }
> +
> +  static class AttributeWrapper implements ParsedHtmlAttribute {
> +    private Node wrapped;
> +
> +    AttributeWrapper(Node wrapped) {
> +      this.wrapped = wrapped;
> +    }
> +
> +    public String getName() {
> +      return wrapped.getNodeName();
> +    }
> +
> +    public String getValue() {
> +      return wrapped.getNodeValue();
> +    }
> +  }
> +}
>
> Added:
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/cajatest.html
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/cajatest.html?rev=705780&view=auto
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/cajatest.html
> (added)
> +++
> incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/cajatest.html
> Fri Oct 17 16:28:33 2008
> @@ -0,0 +1,85 @@
> +<?xml version="not-even-close"?>
> +
> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
> +
> +<!-- a test input for HtmlLexer -->
> +
> +<html>
> +<head>
> +<title>Test File For HtmlLexer &amp; HtmlParser</title>
> +<link rel=stylesheet type="text/css" src=foo/bar.css />
> +<body
> + bgcolor=white
> + linkcolor = "blue"
> + onload="document.writeln(
> +  &quot;&lt;p&gt;properly escaped code in a handler&lt;/p&gt;&quot;);"
> +>
> +
> +<script type="text/javascript"><!--
> +
> +document.writeln("<p>Some initialization code in global context</p>");
> +
> +--></script>
> +
> +<script type="text/javascript">
> +// hi there
> +document.writeln("<p>More initialization</p>");
> +</script>
> +
> +<div id=clickydiv onclick="handleClicky(event)"
> + ondblclick=this.onclick(event);return(false)>
> +Clicky
> +</div>
> +
> +<input id=foo>
> +<gxp:attr name="onchange">alert("&lt;b&gt;hi&lt;/b&gt;");</gxp:attr>
> +</input>
> +
> +<pre>&lt;div id=notarealtag onclick=notcode()&gt;</pre>
> +
> +<!-- some tokenization corner cases -->
> +
> +< notatag <atag/>
> +
> +</ notatag> </redundantlyclosed/>
> +
> +<messyattributes a=b=c d="e"f=g h =i j= k l = m checked n="o"/>
> +
> +< < < all in one text block > > >
> +
> +<xmp>Make sure that <!-- comments don't obscure the xmp close</xmp>
> +
> +<% # some php code here
> +write("<pre>$horriblySyntacticConstruct1</pre>\n\n");
> +%>
> +
> +<script type="text/javascript"><!--
> +alert("hello world");
> +// --></script>
> +
> +<script>/* </script> */alert('hi');</script>
> +<script><!--/* </script> */alert('hi');--></script>
> +
> +<xmp style=color:blue><!--/* </xmp> */alert('hi');--></xmp>
> +
> +<style><!-- p { contentf: '</style>' } --></style>
> +
> +<title>Foo<!-- > </title> --></title>
> +
> +<textarea><!-- Zoicks </textarea>--></textarea>
> +
> +<!-- An escaping text span start may share its U+002D HYPHEN-MINUS
> characters
> +   - with its corresponding escaping text span end. -->
> +<script><!--></script>
> +<script><!---></script>
> +<script><!----></script>
> +
> +</body>
> +</html>
> +
> +<![CDATA[ No such thing as a CDATA> section in HTML ]]>
> +<script>a<b</script>
> +
> +<img src=foo.gif/><a href=><a href=/>
> +
> +<span title=malformed attribs' do=don't id=foo checked
> onclick="a<b">Bar</span>
>
> Copied:
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/HtmlParserTest.java
> (from r704682,
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParserTest.java)
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/HtmlParserTest.java?p2=incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/HtmlParserTest.java&p1=incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParserTest.java&r1=704682&r2=705780&rev=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParserTest.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/HtmlParserTest.java
> Fri Oct 17 16:28:33 2008
> @@ -15,20 +15,30 @@
>  * KIND, either express or implied. See the License for the
>  * specific language governing permissions and limitations under the
> License.
>  */
> -package org.apache.shindig.gadgets.parse.caja;
> +package org.apache.shindig.gadgets.parse;
>
> -import org.apache.shindig.gadgets.parse.ParsedHtmlNode;
> +import org.apache.shindig.gadgets.parse.caja.CajaHtmlParser;
> +import org.apache.shindig.gadgets.parse.nekohtml.NekoHtmlParser;
>
>  import junit.framework.TestCase;
>
>  import java.util.List;
>
> -public class CajaHtmlParserTest extends TestCase {
> -  private final CajaHtmlParser htmlParser = new CajaHtmlParser();
> -
> +public class HtmlParserTest extends TestCase {
> +
> +  private final GadgetHtmlParser cajaParser = new CajaHtmlParser(
> +      new ParseModule.HTMLDocumentProvider());
> +
> +  private final GadgetHtmlParser nekoParser = new NekoHtmlParser(
> +      new ParseModule.HTMLDocumentProvider());
> +
>   public void testParseSimpleString() throws Exception {
> -    List<ParsedHtmlNode> nodes =
> -        htmlParser.parse("content");
> +    parseSimpleString(cajaParser);
> +    parseSimpleString(nekoParser);
> +  }
> +
> +  private void parseSimpleString(GadgetHtmlParser htmlParser) throws
> Exception {
> +    List<ParsedHtmlNode> nodes = htmlParser.parse("content");
>     assertNotNull(nodes);
>     assertEquals(1, nodes.size());
>
> @@ -39,8 +49,13 @@
>     assertNull(node.getChildren());
>     assertNull(node.getTagName());
>   }
> -
> +
>   public void testParseTagWithStringContents() throws Exception {
> +    parseTagWithStringContents(nekoParser);
> +    parseTagWithStringContents(cajaParser);
> +  }
> +
> +  public void parseTagWithStringContents(GadgetHtmlParser htmlParser)
> throws Exception {
>     List<ParsedHtmlNode> nodes =
>         htmlParser.parse("<span>content</span>");
>     assertNotNull(nodes);
> @@ -55,8 +70,13 @@
>     assertEquals("content", node.getChildren().get(0).getText());
>     assertEquals("span", node.getTagName().toLowerCase());
>   }
> -
> +
>   public void testParseTagWithAttributes() throws Exception {
> +    parseTagWithAttributes(nekoParser);
> +    parseTagWithAttributes(cajaParser);
> +  }
> +
> +  void parseTagWithAttributes(GadgetHtmlParser htmlParser) throws
> Exception {
>     List<ParsedHtmlNode> nodes =
>         htmlParser.parse("<div id=\"foo\">content</div>");
>     assertNotNull(nodes);
> @@ -73,8 +93,13 @@
>     assertEquals(1, node.getChildren().size());
>     assertEquals("content", node.getChildren().get(0).getText());
>   }
> -
> +
>   public void testParseStringUnescapesProperly() throws Exception {
> +    parseStringUnescapesProperly(nekoParser);
> +    parseStringUnescapesProperly(cajaParser);
> +  }
> +
> +  void parseStringUnescapesProperly(GadgetHtmlParser htmlParser) throws
> Exception {
>     List<ParsedHtmlNode> nodes =
>         htmlParser.parse("&lt;content&amp;&apos;chrome&apos;&gt;");
>     assertNotNull(nodes);
> @@ -87,8 +112,13 @@
>     assertNull(node.getChildren());
>     assertNull(node.getTagName());
>   }
> -
> +
>   public void testParseNestedContentWithNoCloseForBrAndHr() throws
> Exception {
> +    parseNestedContentWithNoCloseForBrAndHr(nekoParser);
> +    parseNestedContentWithNoCloseForBrAndHr(cajaParser);
> +  }
> +
> +  void parseNestedContentWithNoCloseForBrAndHr(GadgetHtmlParser
> htmlParser) throws Exception {
>     List<ParsedHtmlNode> nodes =
>         htmlParser.parse("<div><br>  and  <hr></div>");
>     assertNotNull(nodes);
> @@ -96,7 +126,7 @@
>
>     ParsedHtmlNode divNode = nodes.get(0);
>     assertNull(divNode.getText());
> -    assertEquals("div", divNode.getTagName());
> +    assertEquals("div", divNode.getTagName().toLowerCase());
>     assertNotNull(divNode.getAttributes());
>     assertEquals(0, divNode.getAttributes().size());
>     assertNotNull(divNode.getChildren());
> @@ -106,12 +136,11 @@
>       // <br>
>       ParsedHtmlNode divChild = divNode.getChildren().get(0);
>       assertNotNull(divChild);
> -      assertEquals("br", divChild.getTagName());
> +      assertEquals("br", divChild.getTagName().toLowerCase());
>       assertNull(divChild.getText());
>       assertNotNull(divChild.getAttributes());
>       assertEquals(0, divChild.getAttributes().size());
> -      assertNotNull(divChild.getChildren());
> -      assertEquals(0, divChild.getChildren().size());
> +      assertNullOrEmpty(divChild.getChildren());
>     }
>
>     {
> @@ -127,16 +156,20 @@
>       // <hr> should be parsed lieniently
>       ParsedHtmlNode divChild = divNode.getChildren().get(2);
>       assertNotNull(divChild);
> -      assertEquals("hr", divChild.getTagName());
> +      assertEquals("hr", divChild.getTagName().toLowerCase());
>       assertNull(divChild.getText());
>       assertNotNull(divChild.getAttributes());
>       assertEquals(0, divChild.getAttributes().size());
> -      assertNotNull(divChild.getChildren());
> -      assertEquals(0, divChild.getChildren().size());
> +      assertNullOrEmpty(divChild.getChildren());
>     }
>   }
> -
> +
>   public void testParseMixedSiblings() throws Exception {
> +    parseMixedSiblings(nekoParser);
> +    parseMixedSiblings(cajaParser);
> +  }
> +
> +  void parseMixedSiblings(GadgetHtmlParser htmlParser) throws Exception {
>     List<ParsedHtmlNode> nodes =
>         htmlParser.parse("content<span>more</span><div id=\"foo\">yet
> more</div>");
>     assertNotNull(nodes);
> @@ -170,13 +203,15 @@
>     }
>   }
>
> -  public void testParseEmptyContent() throws Exception {
> -    String html = "   \n   \t  ";
> -    List<ParsedHtmlNode> nodes = htmlParser.parse(html);
> -    assertNotNull(nodes);
> -    assertEquals(0, nodes.size());
> -  }
> -
>   // TODO: figure out to what extent it makes sense to test "invalid"
>   // HTML, semi-structured HTML, and comment parsing
> +
> +  // Different parsers either return null or empty child lists.
> +  // In particular because Caja is a non-w3c compliant parser
> +  private void assertNullOrEmpty(List l) {
> +    if (l != null && !l.isEmpty()) {
> +      assertTrue(true);
> +    }
> +    return;
> +  }
>  }
>
> Copied:
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/ParseTreeSerializerBenchmark.java
> (from r704682,
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/ParseTreeSerializerTest.java)
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/ParseTreeSerializerBenchmark.java?p2=incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/ParseTreeSerializerBenchmark.java&p1=incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/ParseTreeSerializerTest.java&r1=704682&r2=705780&rev=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/ParseTreeSerializerTest.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/ParseTreeSerializerBenchmark.java
> Fri Oct 17 16:28:33 2008
> @@ -17,85 +17,71 @@
>  */
>  package org.apache.shindig.gadgets.parse;
>
> +import org.apache.shindig.gadgets.parse.caja.CajaHtmlParser;
> +import org.apache.shindig.gadgets.parse.nekohtml.NekoHtmlParser;
> +import org.apache.shindig.gadgets.GadgetException;
> +
> +import org.apache.commons.io.IOUtils;
> +
>  import static org.junit.Assert.assertEquals;
>  import static org.junit.Assert.assertNull;
> -
> -import org.apache.shindig.gadgets.parse.caja.CajaHtmlParser;
> -import org.junit.Test;
> +import org.w3c.dom.Node;
> +import org.w3c.dom.bootstrap.DOMImplementationRegistry;
> +import org.w3c.dom.ls.*;
>
>  import java.io.ByteArrayOutputStream;
>  import java.io.File;
>  import java.io.FileInputStream;
> -import java.util.Arrays;
> -import java.util.LinkedList;
> +import java.io.ByteArrayInputStream;
>  import java.util.List;
>
>  /**
>  * Tests serialization and deserialization of parse trees.
>  */
> -public class ParseTreeSerializerTest {
> -  private static ParseTreeSerializer pts = new ParseTreeSerializer();
> -
> -  public static void main(String[] args) throws Exception {
> -    // Test can be run as standalone program to test out serialization and
> parsing
> -    // performance numbers, using Caja as a parser.
> -    if (args.length != 2) {
> -      System.err.println("Args: <input-file> <num-runs>");
> -      System.exit(1);
> -    }
> -
> -    String fileArg = args[0];
> -    File inputFile = new File(fileArg);
> +public class ParseTreeSerializerBenchmark {
> +  private DOMImplementationRegistry registry =
> DOMImplementationRegistry.newInstance();
> +  private int numRuns;
> +  private String content;
> +  private GadgetHtmlParser cajaParser = new CajaHtmlParser(new
> ParseModule.HTMLDocumentProvider());
> +  private GadgetHtmlParser nekoParser = new NekoHtmlParser(new
> ParseModule.HTMLDocumentProvider());
> +
> +  private ParseTreeSerializerBenchmark(String file, int numRuns) throws
> Exception {
> +    File inputFile = new File(file);
>     if (!inputFile.exists() || !inputFile.canRead()) {
> -      System.err.println("Input file: " + fileArg + " not found or can't
> be read.");
> +      System.err.println("Input file: " + file + " not found or can't be
> read.");
>       System.exit(1);
>     }
> -
> -    String runsArg = args[1];
> -    int numRuns = -1;
> -    try {
> -      numRuns = Integer.parseInt(runsArg);
> -    } catch (Exception e) {
> -      System.err.println("Invalid num-runs argument: " + runsArg + ",
> reason: " + e);
> -    }
> -
> -    FileInputStream fis = new FileInputStream(inputFile);
> -    ByteArrayOutputStream baos = new ByteArrayOutputStream();
> -    byte[] buf = new byte[65535];
> -    int read = -1;
> -    while ((read = fis.read(buf)) > 0) {
> -      baos.write(buf, 0, read);
> -    }
> -    String inputData = new String(baos.toByteArray());
> -
> -    // Caja parser.
> -    System.out.println("Parsing contents of '" + fileArg + "' " + numRuns
> + " times...");
> -    CajaHtmlParser parser = new CajaHtmlParser();
> +    content = new String(IOUtils.toByteArray(new FileInputStream(file)));
> +    this.numRuns = numRuns;
> +
> +    System.out.println("Caja Parse------------------------");
> +    run(cajaParser);
> +    System.out.println("Neko Parse------------------------");
> +    run(nekoParser);
> +  }
> +
> +  private void run(GadgetHtmlParser parser) throws Exception {
>
> -    // Some warmup runs with wait. Enough iterations to trigger the HIT
> +    // Some warmup runs with wait. Enough iterations to trigger the JIT
>     // Wait to allow it to swap execution paths etc...
> -    List<ParsedHtmlNode> nodes = null;
> -    for (int i = 0; i < 10; ++i) {
> -      nodes = parser.parse(inputData);
> -    }
> -    for (int i = 0; i < 10; ++i) {
> -      byte[] ser = pts.serialize(nodes);
> -      List<ParsedHtmlNode> outs = pts.deserialize(ser);
> -    }
> +    timeParseDom(parser, false);
> +    timeParseOld(parser, false);
> +    runLSSerializationTiming(parser, false);
>     Thread.sleep(1000L);
>
> -    long parseStart = System.currentTimeMillis();
> -    for (int i = 0; i < numRuns; ++i) {
> -      nodes = parser.parse(inputData);
> -    }
> +    //System.out.println("Press a key to continue");
> +    //System.in.read();
> +    //System.out.println("Continuing");
> +
> +    timeParseOld(parser, true);
> +    timeParseDom(parser, true);
> +    runLSSerializationTiming(parser, true);
>
> -
> -    long parseMillis = System.currentTimeMillis() - parseStart;
> -
> -    // Serializer/deserializer
> +    /*
>     System.out.println("Serializing and deserializing results of Caja run
> (" +
>         nodes.size() + " top-level nodes, " + numRuns + " runs)\n");
>
> +
>     long serTime = 0, deserTime = 0;
>     for (int i = 0; i < numRuns; ++i) {
>       long serStart = System.currentTimeMillis();
> @@ -106,178 +92,94 @@
>       deserTime += (System.currentTimeMillis() - deserStart);
>       //checkListEquality(nodes, outs);
>     }
> +    */
>
> -    System.out.println("Parsing [" + parseMillis + " ms total: " +
> -        ((double)parseMillis)/numRuns + "ms/run]");
> -    System.out.println("Serialization [" + serTime + " ms total: "
> -        + ((double)serTime)/numRuns + "ms/run]");
> -    System.out.println("Deserialization [" + deserTime + " ms total: "
> -        + ((double)deserTime)/numRuns + "ms/run]");
> -  }
> -
> -  @Test
> -  public void fromTestTreeToBytesAndBack() throws Exception {
> -    List<ParsedHtmlNode> nodes = new LinkedList<ParsedHtmlNode>();
> -    nodes.add(getEverythingNode());
> -    nodes.add(getEverythingNode());
> -    checkSerializationPasses(nodes);
> +    //System.out.println("Serialization [" + serTime + " ms total: "
> +    //    + ((double)serTime)/numRuns + "ms/run]");
> +    //System.out.println("Deserialization [" + deserTime + " ms total: "
> +    //    + ((double)deserTime)/numRuns + "ms/run]");
>   }
> -
> -  @Test
> -  public void cantDeserializeDifferentVersion() throws Exception {
> -    List<ParsedHtmlNode> nodes = new LinkedList<ParsedHtmlNode>();
> -    nodes.add(getEverythingNode());
> -    byte[] serialized = pts.serialize(nodes);
> -    List<ParsedHtmlNode> back = pts.deserialize(serialized);
> -    checkListEquality(nodes, back);
> -
> -    // This never happens in a given run of code, but is used to simulate
> -    // the version number of cached data getting out of sync with
> processing code.
> -    serialized[0]++;
> -    assertNull(pts.deserialize(serialized));
> -  }
> -
> -  @Test
> -  public void fromCajaTreeToBytesAndBack() throws Exception {
> -    String bigHTML = "";
> -    for (int i = 0; i < 100; ++i) {
> -      bigHTML += "<parent pkey=\"pval\">parentText<child
> ckey=\"cval\">childText</child></parent>";
> +
> +  private void timeParseDom(GadgetHtmlParser parser, boolean output)
> throws GadgetException {
> +    long parseStart = System.currentTimeMillis();
> +    for (int i = 0; i < 10; ++i) {
> +      parser.parseDom(content);
>     }
> -    checkSerializationPasses(new CajaHtmlParser().parse(bigHTML));
> -  }
> +    long parseMillis = System.currentTimeMillis() - parseStart;
>
> -  private ParsedHtmlNode getEverythingNode() {
> -    // Return node containing a text node and a child node with
> attributes.
> -    ParsedHtmlNode childText = TestParsedHtmlNode.getText("childText");
> -    String[] childNVs = { "child", "cval" };
> -    ParsedHtmlNode[] childChildren = { childText };
> -    ParsedHtmlNode child = TestParsedHtmlNode.getTag("childNode",
> childNVs, childChildren);
> -
> -    ParsedHtmlNode parentText = TestParsedHtmlNode.getText("parentText");
> -    String[] parentNVs = { "parent", "pval" };
> -    ParsedHtmlNode[] children = { child };
> -    return TestParsedHtmlNode.getTag("parentNode", parentNVs, children);
> -  }
> -
> -  private static void checkSerializationPasses(List<ParsedHtmlNode> raw)
> throws Exception {
> -    byte[] serialized = pts.serialize(raw);
> -    List<ParsedHtmlNode> fromTheDead = pts.deserialize(serialized);
> -    checkListEquality(raw, fromTheDead);
> -  }
> -
> -  private static void checkListEquality(List<ParsedHtmlNode> raw,
> List<ParsedHtmlNode> outs) {
> -    List<ParsedHtmlNode> rawTestable = new LinkedList<ParsedHtmlNode>();
> -    for (ParsedHtmlNode rawNode : raw) {
> -      rawTestable.add(TestParsedHtmlNode.get(rawNode));
> -    }
> -    List<ParsedHtmlNode> outTestable = new LinkedList<ParsedHtmlNode>();
> -    for (ParsedHtmlNode inNode : outs) {
> -      outTestable.add(TestParsedHtmlNode.get(inNode));
> +    if (output) {
> +      System.out.println("Parsing W3C DOM [" + parseMillis + " ms total: "
> +
> +          ((double)parseMillis)/numRuns + "ms/run]");
>     }
> -    assertEquals(rawTestable, outTestable);
>   }
> -
> -  // Test class providing both a fake ParsedHtmlNode class as well as
> -  // one that provides equality testing for ParsedHtmlNodes of any
> provenance
> -  private static class TestParsedHtmlNode implements ParsedHtmlNode {
> -    private String tag;
> -    private String text;
> -    private List<ParsedHtmlAttribute> attribs;
> -    private List<ParsedHtmlNode> children;
> -
> -    public static ParsedHtmlNode get(ParsedHtmlNode in) {
> -      TestParsedHtmlNode node = new TestParsedHtmlNode();
> -      node.text = in.getText();
> -      if (node.text == null) {
> -        node.tag = in.getTagName();
> -        node.attribs = new LinkedList<ParsedHtmlAttribute>();
> -        for (ParsedHtmlAttribute pha : in.getAttributes()) {
> -          node.attribs.add(new TestParsedHtmlAttribute(pha.getName(),
> pha.getValue()));
> -        }
> -        node.children = new LinkedList<ParsedHtmlNode>();
> -        for (ParsedHtmlNode child : in.getChildren()) {
> -          node.children.add(TestParsedHtmlNode.get(child));
> -        }
> -      }
> -      return node;
> -    }
> -
> -    public static ParsedHtmlNode getTag(String tag, String[] nvpairs,
> ParsedHtmlNode[] children) {
> -      TestParsedHtmlNode node = new TestParsedHtmlNode();
> -      node.tag = tag;
> -      node.attribs = new LinkedList<ParsedHtmlAttribute>();
> -      for (int i = 0; i < nvpairs.length; i += 2) {
> -        node.attribs.add(new TestParsedHtmlAttribute(nvpairs[i],
> nvpairs[i+1]));
> -      }
> -      // Just in case somehow Arrays.asList() doesn't return a List
> subclassing
> -      // AbstractList (whose .equals() method doesn't check list type)
> -      node.children = new LinkedList<ParsedHtmlNode>();
> -      node.children.addAll(Arrays.asList(children));
> -      return node;
> -    }
> -
> -    public static ParsedHtmlNode getText(String text) {
> -      TestParsedHtmlNode node = new TestParsedHtmlNode();
> -      node.text = text;
> -      return node;
> -    }
>
> -    public List<ParsedHtmlAttribute> getAttributes() {
> -      return attribs;
> +  private void timeParseOld(GadgetHtmlParser parser, boolean output)
> throws GadgetException {
> +    long parseStart = System.currentTimeMillis();
> +    List<ParsedHtmlNode> nodes;
> +    for (int i = 0; i < numRuns; ++i) {
> +      nodes = parser.parse(content);
>     }
> +    long parseMillis = System.currentTimeMillis() - parseStart;
>
> -    public List<ParsedHtmlNode> getChildren() {
> -      return children;
> +    if (output) {
> +      System.out.println("Parsing [" + parseMillis + " ms total: " +
> +          ((double)parseMillis)/numRuns + "ms/run]");
>     }
> +  }
>
> -    public String getTagName() {
> -      return tag;
> -    }
> +  private void runLSSerializationTiming(GadgetHtmlParser parser, boolean
> outputResult) throws Exception {
> +    Node n = parser.parseDom(content);
> +    DOMImplementationLS impl = (DOMImplementationLS)
> registry.getDOMImplementation("LS");
> +    ByteArrayOutputStream baos;
> +    baos = new ByteArrayOutputStream(content.length() * 2);
> +    LSSerializer writer = impl.createLSSerializer();
> +    LSParser lsParser =
> impl.createLSParser(LSParser.ACTION_APPEND_AS_CHILDREN, null);
>
> -    public String getText() {
> -      return text;
> +    long serTime = 0, deserTime = 0;
> +    for (int i = 0; i < numRuns; ++i) {
> +      long serStart = System.currentTimeMillis();
> +      LSOutput output = impl.createLSOutput();
> +      baos.reset();
> +      output.setByteStream(baos);
> +      writer.write(n, output);
> +      serTime += (System.currentTimeMillis() - serStart);
> +      LSInput input = impl.createLSInput();
> +      input.setByteStream(new ByteArrayInputStream(baos.toByteArray()));
> +      long deserStart = System.currentTimeMillis();
> +      //XmlUtil.parse(new String(baos.toByteArray()));
> +      lsParser.parse(input);
> +      deserTime += (System.currentTimeMillis() - deserStart);
> +      //checkListEquality(nodes, outs);
>     }
> -
> -    @Override
> -    public boolean equals(Object other) {
> -      if (!(other instanceof TestParsedHtmlNode)) {
> -        return false;
> -      }
> -      TestParsedHtmlNode onode = (TestParsedHtmlNode)other;
> -      if (this.text != null) {
> -        return this.text.equals(onode.text);
> -      }
> -      return (this.tag.equals(onode.tag) &&
> -              this.attribs.equals(onode.attribs) &&
> -              this.children.equals(onode.children));
> +
> +    if (outputResult) {
> +      System.out.println("LS Serialization [" + serTime + " ms total: "
> +          + ((double)serTime)/numRuns + "ms/run]");
> +      System.out.println("LS Deserialization [" + deserTime + " ms total:
> "
> +          + ((double)deserTime)/numRuns + "ms/run]");
>     }
>   }
> -
> -  private static class TestParsedHtmlAttribute implements
> ParsedHtmlAttribute {
> -    private String name;
> -    private String value;
> -
> -    private TestParsedHtmlAttribute(String name, String value) {
> -      this.name = name;
> -      this.value = value;
> -    }
>
> -    public String getName() {
> -      return name;
> +  public static void main(String[] args) {
> +    // Test can be run as standalone program to test out serialization and
> parsing
> +    // performance numbers, using Caja as a parser.
> +    if (args.length != 2) {
> +      System.err.println("Args: <input-file> <num-runs>");
> +      System.exit(1);
>     }
>
> -    public String getValue() {
> -      return value;
> +    String fileArg = args[0];
> +    String runsArg = args[1];
> +    int numRuns = -1;
> +    try {
> +      numRuns = Integer.parseInt(runsArg);
> +    } catch (Exception e) {
> +      System.err.println("Invalid num-runs argument: " + runsArg + ",
> reason: " + e);
>     }
> -
> -    @Override
> -    public boolean equals(Object other) {
> -      if (!(other instanceof TestParsedHtmlAttribute)) {
> -        return false;
> -      }
> -      TestParsedHtmlAttribute oattr = (TestParsedHtmlAttribute)other;
> -      return (this.name.equals(oattr.name) &&
> -              this.value.equals(oattr.value));
> +    try {
> +      new ParseTreeSerializerBenchmark(fileArg, numRuns);
> +    } catch (Exception e) {
> +      e.printStackTrace();
>     }
>   }
>  }
>
> Modified:
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/MutableContentTest.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/MutableContentTest.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/MutableContentTest.java
> (original)
> +++
> incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/MutableContentTest.java
> Fri Oct 17 16:28:33 2008
> @@ -18,16 +18,15 @@
>  */
>  package org.apache.shindig.gadgets.rewrite;
>
> +import org.apache.shindig.gadgets.parse.GadgetHtmlNode;
> +import org.apache.shindig.gadgets.parse.ParseModule;
> +import org.apache.shindig.gadgets.parse.caja.CajaHtmlParser;
> +
>  import static org.junit.Assert.assertEquals;
>  import static org.junit.Assert.assertNotSame;
>  import static org.junit.Assert.assertSame;
>  import static org.junit.Assert.assertTrue;
>  import static org.junit.Assert.fail;
> -
> -import org.apache.shindig.gadgets.parse.GadgetHtmlNode;
> -import org.apache.shindig.gadgets.parse.caja.CajaHtmlParser;
> -import org.apache.shindig.gadgets.rewrite.MutableContent;
> -
>  import org.junit.Before;
>  import org.junit.Test;
>
> @@ -39,7 +38,7 @@
>     // Note dependency on CajaHtmlParser - this isn't particularly ideal
> but is
>     // sufficient given that this test doesn't exercise the parser
> extensively at all,
>     // instead focusing on the additional utility provided by
> MutableHtmlContent
> -    mhc = new MutableContent(new CajaHtmlParser());
> +    mhc = new MutableContent(new CajaHtmlParser(new
> ParseModule.HTMLDocumentProvider()));
>     mhc.setContent("DEFAULT VIEW");
>   }
>
>
> Modified:
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/oauth/OAuthConsumerRequestAuthenticationHandler.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/oauth/OAuthConsumerRequestAuthenticationHandler.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/oauth/OAuthConsumerRequestAuthenticationHandler.java
> (original)
> +++
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/oauth/OAuthConsumerRequestAuthenticationHandler.java
> Fri Oct 17 16:28:33 2008
> @@ -23,12 +23,13 @@
>
>  import com.google.inject.Inject;
>
> +import org.apache.commons.lang.StringUtils;
> +
>  import net.oauth.OAuth;
> +import net.oauth.OAuthException;
>  import net.oauth.OAuthMessage;
>  import net.oauth.server.OAuthServlet;
>
> -import org.apache.commons.lang.StringUtils;
> -
>  import java.io.IOException;
>
>  import javax.servlet.http.HttpServletRequest;
> @@ -64,10 +65,14 @@
>       return null;
>     }
>
> -    if (service.thirdPartyHasAccessToUser(requestMessage, containerKey,
> userId)) {
> -      return service.getSecurityToken(containerKey, userId);
> -    } else {
> -      return null;
> +    try {
> +      if (service.thirdPartyHasAccessToUser(requestMessage, containerKey,
> userId)) {
> +        return service.getSecurityToken(containerKey, userId);
> +      } else {
> +        return null;
> +      }
> +    } catch (OAuthException oae) {
> +      throw new InvalidAuthenticationException(oae.getMessage(), oae);
>     }
>   }
>
>
> Modified:
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthLookupService.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthLookupService.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthLookupService.java
> (original)
> +++
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthLookupService.java
> Fri Oct 17 16:28:33 2008
> @@ -22,12 +22,13 @@
>
>  import com.google.inject.ImplementedBy;
>
> +import net.oauth.OAuthException;
>  import net.oauth.OAuthMessage;
>
>  @ImplementedBy(SampleContainerOAuthLookupService.class)
>
>  public interface OAuthLookupService {
>   boolean thirdPartyHasAccessToUser(OAuthMessage message, String appUrl,
> -      String userId);
> +      String userId) throws OAuthException;
>   SecurityToken getSecurityToken(String appUrl, String userId);
>  }
>
> Modified:
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleContainerOAuthLookupService.java
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleContainerOAuthLookupService.java?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> ---
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleContainerOAuthLookupService.java
> (original)
> +++
> incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleContainerOAuthLookupService.java
> Fri Oct 17 16:28:33 2008
> @@ -57,13 +57,15 @@
>       "8355", "SocialActivitiesWorldSharedSecret"
>   );
>
> -  public boolean thirdPartyHasAccessToUser(OAuthMessage message, String
> appUrl, String userId) {
> +  public boolean thirdPartyHasAccessToUser(OAuthMessage message, String
> appUrl, String userId)
> +    throws OAuthException {
>     String appId = getAppId(appUrl);
>     return hasValidSignature(message, appUrl, appId)
>         && userHasAppInstalled(userId, appId);
>   }
>
> -  private boolean hasValidSignature(OAuthMessage message, String appUrl,
> String appId) {
> +  private boolean hasValidSignature(OAuthMessage message, String appUrl,
> String appId)
> +      throws OAuthException {
>     String sharedSecret = sampleContainerSharedSecrets.get(appId);
>     if (sharedSecret == null) {
>       return false;
> @@ -76,12 +78,10 @@
>     SimpleOAuthValidator validator = new SimpleOAuthValidator();
>     try {
>       validator.validateMessage(message, accessor);
> -    } catch (OAuthException e) {
> -      return false;
>     } catch (IOException e) {
> -      return false;
> +      throw new OAuthException(e);
>     } catch (URISyntaxException e) {
> -      return false;
> +      throw new OAuthException(e);
>     }
>
>     return true;
>
> Modified: incubator/shindig/trunk/pom.xml
> URL:
> http://svn.apache.org/viewvc/incubator/shindig/trunk/pom.xml?rev=705780&r1=705779&r2=705780&view=diff
>
> ==============================================================================
> --- incubator/shindig/trunk/pom.xml (original)
> +++ incubator/shindig/trunk/pom.xml Fri Oct 17 16:28:33 2008
> @@ -616,6 +616,9 @@
>           <includes>
>             <include>**/*.java</include>
>           </includes>
> +          <excludes>
> +            <exclude>**/jsunit/**/*</exclude>
> +          </excludes>
>         </configuration>
>       </plugin>
>     </plugins>
> @@ -1007,6 +1010,16 @@
>         <artifactId>xpp3</artifactId>
>         <version>1.1.3.3</version>
>       </dependency>
> +      <dependency>
> +        <groupId>net.sourceforge.nekohtml</groupId>
> +        <artifactId>nekohtml</artifactId>
> +        <version>1.9.9</version>
> +      </dependency>
> +      <dependency>
> +        <groupId>xerces</groupId>
> +        <artifactId>xercesImpl</artifactId>
> +        <version>2.9.1</version>
> +      </dependency>
>     </dependencies>
>   </dependencyManagement>
>  </project>
>
>
>