Author: etnu
Date: Sun Jun  8 14:45:04 2008
New Revision: 664562

URL: http://svn.apache.org/viewvc?rev=664562&view=rev
Log:
Added support for Link elements, facilitating lifecycle events and link 
metadata, as required by SHINDIG-341.

This just adds the elements to ModulePrefs and the metadata output handler. It 
does not perform any actions on lifecycle events at the moment, such as pinging 
the url end points.

It's not clear if the task of hitting the end points is the job of Shindig or 
not.


Added:
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/LinkSpec.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/LinkSpecTest.java
Modified:
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Icon.java
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/ModulePrefs.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/JsonRpcHandlerTest.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/ModulePrefsTest.java

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java?rev=664562&r1=664561&r2=664562&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java
 Sun Jun  8 14:45:04 2008
@@ -23,6 +23,7 @@
 import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetServer;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
+import org.apache.shindig.gadgets.spec.LinkSpec;
 import org.apache.shindig.gadgets.spec.ModulePrefs;
 import org.apache.shindig.gadgets.spec.UserPref;
 import org.apache.shindig.gadgets.spec.View;
@@ -49,8 +50,8 @@
 public class JsonRpcHandler {
 
   private final Executor executor;
-  private GadgetServer server;
-  private UrlGenerator urlGenerator;
+  private final GadgetServer server;
+  private final UrlGenerator urlGenerator;
 
   /**
    * Processes a JSON request.
@@ -152,6 +153,12 @@
         Set<String> feats = prefs.getFeatures().keySet();
         String[] features = feats.toArray(new String[feats.size()]);
 
+        // Links
+        JSONObject links = new JSONObject();
+        for (LinkSpec link : prefs.getLinks().values()) {
+          links.put(link.getRel(), link.getHref());
+        }
+
         JSONObject userPrefs = new JSONObject();
 
         // User pref specs
@@ -175,6 +182,7 @@
                   .put("views", views)
                   .put("features", features)
                   .put("userPrefs", userPrefs)
+                  .put("links", links)
 
                   // extended meta data
                   .put("directoryTitle", prefs.getDirectoryTitle())

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Icon.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Icon.java?rev=664562&r1=664561&r2=664562&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Icon.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Icon.java
 Sun Jun  8 14:45:04 2008
@@ -73,11 +73,11 @@
   @Override
   public String toString() {
     StringBuilder buf = new StringBuilder();
-    buf.append("<Icon type=\"")
-       .append(type)
-       .append("\" mode=\"")
-       .append(mode)
-       .append("\">")
+    buf.append("<Icon type='").append(type).append('\'');
+    if (mode != null) {
+      buf.append(" mode='").append(mode).append('\'');
+    }
+    buf.append('>')
        .append(content)
        .append("</Icon>");
     return buf.toString();

Added: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/LinkSpec.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/LinkSpec.java?rev=664562&view=auto
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/LinkSpec.java
 (added)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/LinkSpec.java
 Sun Jun  8 14:45:04 2008
@@ -0,0 +1,76 @@
+/*
+ * 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.spec;
+
+import org.apache.shindig.common.xml.XmlUtil;
+import org.apache.shindig.gadgets.Substitutions;
+
+import org.w3c.dom.Element;
+
+import java.net.URI;
+
+/**
+ * Represents /ModulePrefs/Link elements.
+ */
+public class LinkSpec {
+
+  /**
+   * Link/@rel
+   */
+  private final String rel;
+  public String getRel() {
+    return rel;
+  }
+
+  /**
+   * Link/@href
+   */
+  private final URI href;
+  public URI getHref() {
+    return href;
+  }
+
+  /**
+   * Performs variable substitution on all visible elements.
+   */
+  public LinkSpec substitute(Substitutions substitutions) {
+    return new LinkSpec(this, substitutions);
+  }
+
+  @Override
+  public String toString() {
+    return "<Link rel='" + rel + "' href='" + href.toString() + "'/>";
+  }
+
+  public LinkSpec(Element element) throws SpecParserException {
+    rel = XmlUtil.getAttribute(element, "rel");
+    if (rel == null) {
+      throw new SpecParserException("Link/@rel is required!");
+    }
+    href = XmlUtil.getUriAttribute(element, "href");
+    if (href == null) {
+      throw new SpecParserException("Link/@href is required!");
+    }
+  }
+
+  private LinkSpec(LinkSpec rhs, Substitutions substitutions) {
+    rel = substitutions.substituteString(null, rhs.rel);
+    href = substitutions.substituteUri(null, rhs.href);
+  }
+}

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/ModulePrefs.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/ModulePrefs.java?rev=664562&r1=664561&r2=664562&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/ModulePrefs.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/ModulePrefs.java
 Sun Jun  8 14:45:04 2008
@@ -320,8 +320,8 @@
   }
 
   /**
-   * ModuleSpec.Require
-   * ModuleSpec.Optional
+   * ModuleSpec/Require
+   * ModuleSpec/Optional
    */
   private final Map<String, Feature> features;
   public Map<String, Feature> getFeatures() {
@@ -329,7 +329,7 @@
   }
 
   /**
-   * ModuleSpec.Preload
+   * ModuleSpec/Preload
    */
   private final List<Preload> preloads;
   public List<Preload> getPreloads() {
@@ -337,15 +337,15 @@
   }
 
   /**
-   * ModuleSpec.Icon
+   * ModuleSpec/Icon
    */
-  private List<Icon> icons;
+  private final List<Icon> icons;
   public List<Icon> getIcons() {
     return icons;
   }
 
   /**
-   * ModuleSpec.Locale
+   * ModuleSpec/Locale
    */
   private final Map<Locale, LocaleSpec> locales;
   public Map<Locale, LocaleSpec> getLocales() {
@@ -353,6 +353,14 @@
   }
 
   /**
+   * ModuleSpec/Link
+   */
+  private final Map<String, LinkSpec> links;
+  public Map<String, LinkSpec> getLinks() {
+    return links;
+  }
+
+  /**
    * Attempts to retrieve a valid LocaleSpec for the given Locale.
    * First tries to find an exact language / country match.
    * Then tries to find a match for language / all.
@@ -385,24 +393,7 @@
    * @param substituter
    */
   public ModulePrefs substitute(Substitutions substituter) {
-    ModulePrefs prefs = new ModulePrefs(this);
-
-    // Icons, if any
-    if (icons.isEmpty()) {
-      prefs.icons = Collections.emptyList();
-    } else {
-      List<Icon> iconList = new ArrayList<Icon>(icons.size());
-      for (Icon icon : icons) {
-        iconList.add(icon.substitute(substituter));
-      }
-      prefs.icons = Collections.unmodifiableList(iconList);
-    }
-
-    for (Map.Entry<String, String> attr : attributes.entrySet()) {
-      String substituted = substituter.substituteString(null, attr.getValue());
-      prefs.attributes.put(attr.getKey(), substituted);
-    }
-    return prefs;
+    return new ModulePrefs(this, substituter);
   }
 
 
@@ -446,6 +437,9 @@
     for (LocaleSpec locale : locales.values()) {
       buf.append(locale).append('\n');
     }
+    for (LinkSpec link : links.values()) {
+      buf.append(link).append('\n');
+    }
     buf.append("</ModulePrefs>");
     return buf.toString();
   }
@@ -474,28 +468,57 @@
     FeatureVisitor featureVisitor = new FeatureVisitor();
     IconVisitor iconVisitor = new IconVisitor();
     LocaleVisitor localeVisitor = new LocaleVisitor(specUrl);
-    Map<String, ElementVisitor> visitors = new HashMap<String, 
ElementVisitor>(5,1);
+    LinkVisitor linkVisitor = new LinkVisitor();
+
+    Map<String, ElementVisitor> visitors
+        = new HashMap<String, ElementVisitor>(6, 1);
     visitors.put("Preload", preloadVisitor);
     visitors.put("Optional", featureVisitor);
     visitors.put("Require", featureVisitor);
     visitors.put("Icon", iconVisitor);
     visitors.put("Locale", localeVisitor);
+    visitors.put("Link", linkVisitor);
+
     walk(element, visitors);
+
     preloads = Collections.unmodifiableList(preloadVisitor.preloads);
     features = Collections.unmodifiableMap(featureVisitor.features);
     icons = Collections.unmodifiableList(iconVisitor.icons);
     locales = Collections.unmodifiableMap(localeVisitor.locales);
+    links = Collections.unmodifiableMap(linkVisitor.links);
   }
 
   /**
-   * Creates an empty module prefs for substitute() to use.
+   * Produces a new, substituted ModulePrefs
    */
-  private ModulePrefs(ModulePrefs prefs) {
-    attributes = new HashMap<String, String>();
+  private ModulePrefs(ModulePrefs prefs, Substitutions substituter) {
     categories = prefs.getCategories();
-    preloads = prefs.getPreloads();
     features = prefs.getFeatures();
     locales = prefs.getLocales();
+
+    // TODO: Preload should have substitutions performed as well.
+    preloads = prefs.getPreloads();
+
+    List<Icon> icons = new ArrayList<Icon>(prefs.icons.size());
+    for (Icon icon : prefs.icons) {
+      icons.add(icon.substitute(substituter));
+    }
+    this.icons = Collections.unmodifiableList(icons);
+
+    Map<String, LinkSpec> links = new HashMap<String, 
LinkSpec>(prefs.links.size());
+    for (LinkSpec link : prefs.links.values()) {
+      LinkSpec sub = link.substitute(substituter);
+      links.put(sub.getRel(), sub);
+    }
+    this.links = Collections.unmodifiableMap(links);
+
+    Map<String, String> attributes
+        = new HashMap<String, String>(prefs.attributes.size());
+    for (Map.Entry<String, String> attr : prefs.attributes.entrySet()) {
+      String substituted = substituter.substituteString(null, attr.getValue());
+      attributes.put(attr.getKey(), substituted);
+    }
+    this.attributes = Collections.unmodifiableMap(attributes);
   }
 }
 
@@ -504,7 +527,7 @@
 }
 
 /**
- * Processes ModulePrefs.Preload into a list.
+ * Processes ModulePrefs/Preload into a list.
  */
 class PreloadVisitor implements ElementVisitor {
   final List<Preload> preloads = new LinkedList<Preload>();
@@ -515,7 +538,7 @@
 }
 
 /**
- * Processes ModulePrefs.Require and ModulePrefs.Optional
+ * Processes ModulePrefs/Require and ModulePrefs/Optional
  */
 class FeatureVisitor implements ElementVisitor {
   final Map<String, Feature> features = new HashMap<String, Feature>();
@@ -526,7 +549,7 @@
 }
 
 /**
- * Processes ModulePrefs.Icon
+ * Processes ModulePrefs/Icon
  */
 class IconVisitor implements ElementVisitor {
   final List<Icon> icons = new LinkedList<Icon>();
@@ -536,7 +559,7 @@
 }
 
 /**
- * Process ModulePrefs.Locale
+ * Process ModulePrefs/Locale
  */
 class LocaleVisitor implements ElementVisitor {
   final URI base;
@@ -550,3 +573,15 @@
     this.base = base;
   }
 }
+
+/**
+ * Process ModulePrefs/Link
+ */
+class LinkVisitor implements ElementVisitor {
+  final Map<String, LinkSpec> links = new HashMap<String, LinkSpec>();
+
+  public void visit(Element element) throws SpecParserException {
+    LinkSpec link = new LinkSpec(element);
+    links.put(link.getRel(), link);
+  }
+}

Modified: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/JsonRpcHandlerTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/JsonRpcHandlerTest.java?rev=664562&r1=664561&r2=664562&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/JsonRpcHandlerTest.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/JsonRpcHandlerTest.java
 Sun Jun  8 14:45:04 2008
@@ -43,9 +43,13 @@
   private static final String SPEC_TITLE2 = "JSON-TEST2";
   private static final int PREFERRED_HEIGHT = 100;
   private static final int PREFERRED_WIDTH = 242;
+  private static final String LINK_REL = "rel";
+  private static final String LINK_HREF = "http://example.org/foo";;
   private static final String SPEC_XML
       = "<Module>" +
-        "<ModulePrefs title=\"" + SPEC_TITLE + "\"/>" +
+        "<ModulePrefs title=\"" + SPEC_TITLE + "\">" +
+        "  <Link rel='" + LINK_REL + "' href='" + LINK_HREF + "'/>" +
+        "</ModulePrefs>" +
         "<Content type=\"html\"" +
         " preferred_height = \"" + PREFERRED_HEIGHT + "\"" +
         " preferred_width = \"" + PREFERRED_WIDTH + "\"" +
@@ -96,8 +100,11 @@
         .getJSONObject(GadgetSpec.DEFAULT_VIEW);
     assertEquals(PREFERRED_HEIGHT, view.getInt("preferredHeight"));
     assertEquals(PREFERRED_WIDTH, view.getInt("preferredWidth"));
+    assertEquals(LINK_HREF, gadget.getJSONObject("links").getString(LINK_REL));
   }
 
+  // TODO: Verify that user pref specs are returned correctly.
+
   public void testMultipleGadgets() throws Exception {
     JSONArray gadgets = new JSONArray()
      .put(createGadget(SPEC_URL.toString(), 0, null))
@@ -119,13 +126,23 @@
     verify();
 
     JSONArray outGadgets = response.getJSONArray("gadgets");
-    JSONObject gadget = outGadgets.getJSONObject(0);
-    if (gadget.getString("url").equals(SPEC_URL.toString())) {
-      assertEquals(SPEC_TITLE, gadget.getString("title"));
-      assertEquals(0, gadget.getInt("moduleId"));
-    } else {
-      assertEquals(SPEC_TITLE2, gadget.getString("title"));
-      assertEquals(1, gadget.getInt("moduleId"));
+
+    boolean first = false;
+    boolean second = false;
+    for (int i = 0, j = outGadgets.length(); i < j; ++i) {
+      JSONObject gadget = outGadgets.getJSONObject(i);
+      if (gadget.getString("url").equals(SPEC_URL.toString())) {
+        assertEquals(SPEC_TITLE, gadget.getString("title"));
+        assertEquals(0, gadget.getInt("moduleId"));
+        first = true;
+      } else {
+        assertEquals(SPEC_TITLE2, gadget.getString("title"));
+        assertEquals(1, gadget.getInt("moduleId"));
+        second = true;
+      }
     }
+
+    assertTrue("First gadget not returned!", first);
+    assertTrue("Second gadget not returned!", second);
   }
 }

Added: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/LinkSpecTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/LinkSpecTest.java?rev=664562&view=auto
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/LinkSpecTest.java
 (added)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/LinkSpecTest.java
 Sun Jun  8 14:45:04 2008
@@ -0,0 +1,95 @@
+/*
+ * 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.spec;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.shindig.common.xml.XmlUtil;
+import org.apache.shindig.gadgets.Substitutions;
+
+import org.junit.Test;
+
+import java.net.URI;
+
+/**
+ * Tests for Link.
+ */
+public class LinkSpecTest {
+  private static final String REL_VALUE = "foo";
+  private static final URI HREF_VALUE = URI.create("http://example.org/foo";);
+
+  @Test
+  public void parseBasicLink() throws Exception {
+    String xml = "<Link rel='" + REL_VALUE + "' href='" + HREF_VALUE + "'/>";
+
+    LinkSpec link = new LinkSpec(XmlUtil.parse(xml));
+
+    assertEquals(REL_VALUE, link.getRel());
+    assertEquals(HREF_VALUE, link.getHref());
+  }
+
+  @Test
+  public void substitutionsPerformed() throws Exception {
+    String rel = "foo.bar";
+    String href = "jp-DE.xml";
+    URI expectedHref = URI.create("http://example.org/jp-DE.xml";);
+    String xml = "<Link rel='__MSG_rel__' 
href='http://example.org/__MSG_href__'/>";
+
+    LinkSpec link = new LinkSpec(XmlUtil.parse(xml));
+    Substitutions substitutions = new Substitutions();
+    substitutions.addSubstitution(Substitutions.Type.MESSAGE, "rel", rel);
+    substitutions.addSubstitution(Substitutions.Type.MESSAGE, "href", href);
+    LinkSpec substituted = link.substitute(substitutions);
+
+    assertEquals(rel, substituted.getRel());
+    assertEquals(expectedHref, substituted.getHref());
+  }
+
+  @Test(expected = SpecParserException.class)
+  public void parseNoRel() throws Exception {
+    String xml = "<Link href='foo'/>";
+    new LinkSpec(XmlUtil.parse(xml));
+  }
+
+  @Test(expected = SpecParserException.class)
+  public void parseNoHref() throws Exception {
+    String xml = "<Link rel='bar'/>";
+    new LinkSpec(XmlUtil.parse(xml));
+  }
+
+  @Test(expected = SpecParserException.class)
+  public void parseBogusHref() throws Exception {
+    String xml = "<Link rel='foo' href='$%^$#%$#$%'/>";
+    new LinkSpec(XmlUtil.parse(xml));
+  }
+
+  @Test
+  public void toStringIsSane() throws Exception {
+    String xml = "<Link rel='" + REL_VALUE + "' href='" + HREF_VALUE + "'/>";
+
+    LinkSpec link = new LinkSpec(XmlUtil.parse(xml));
+    LinkSpec link2 = new LinkSpec(XmlUtil.parse(link.toString()));
+
+    assertEquals(link.getRel(), link2.getRel());
+    assertEquals(link.getHref(), link2.getHref());
+    assertEquals(REL_VALUE, link2.getRel());
+    assertEquals(HREF_VALUE, link2.getHref());
+
+  }
+}

Modified: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/ModulePrefsTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/ModulePrefsTest.java?rev=664562&r1=664561&r2=664562&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/ModulePrefsTest.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/ModulePrefsTest.java
 Sun Jun  8 14:45:04 2008
@@ -19,40 +19,54 @@
 
 package org.apache.shindig.gadgets.spec;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 import org.apache.shindig.common.xml.XmlUtil;
 import org.apache.shindig.gadgets.Substitutions;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.net.URI;
 import java.util.Locale;
 
-public class ModulePrefsTest extends TestCase {
+public class ModulePrefsTest {
   private static final URI SPEC_URL = URI.create("http://example.org/g.xml";);
+  private static final String FULL_XML
+      = "<ModulePrefs" +
+        " title='title'" +
+        " title_url='title_url'" +
+        " description='description'" +
+        " author='author'" +
+        " author_email='author_email'" +
+        " screenshot='screenshot'" +
+        " thumbnail='thumbnail'" +
+        " directory_title='directory_title'" +
+        " width='1'" +
+        " height='2'" +
+        " scrolling='true'" +
+        " category='category'" +
+        " category2='category2'" +
+        " author_affiliation='author_affiliation'" +
+        " author_location='author_location'" +
+        " author_photo='author_photo'" +
+        " author_aboutme='author_aboutme'" +
+        " author_quote='author_quote'" +
+        " author_link='author_link'" +
+        " show_stats='true'" +
+        " show_in_directory='true'" +
+        " singleton='true'>" +
+        "  <Require feature='require'/>" +
+        "  <Optional feature='optional'/>" +
+        "  <Preload href='http://example.org' authz='signed'/>" +
+        "  <Icon/>" +
+        "  <Locale/>" +
+        "  <Link rel='link' href='http://example.org/link'/>" +
+        "</ModulePrefs>";
 
-  public void testBasic() throws Exception {
-    String xml = "<ModulePrefs" +
-                 " title=\"title\"" +
-                 " title_url=\"title_url\"" +
-                 " description=\"description\"" +
-                 " author=\"author\"" +
-                 " author_email=\"author_email\"" +
-                 " screenshot=\"screenshot\"" +
-                 " thumbnail=\"thumbnail\"" +
-                 " directory_title=\"directory_title\"" +
-                 " width=\"1\"" +
-                 " height=\"2\"" +
-                 " scrolling=\"true\"" +
-                 " category=\"category\"" +
-                 " category2=\"category2\">" +
-                 "  <Require feature=\"require\"/>" +
-                 "  <Optional feature=\"optional\"/>" +
-                 "  <Preload href=\"http://example.org\"; authz=\"signed\"/>" +
-                 "  <Icon/>" +
-                 "  <Locale/>" +
-                 "</ModulePrefs>";
-    ModulePrefs prefs = new ModulePrefs(XmlUtil.parse(xml), SPEC_URL);
-
+  private void doAsserts(ModulePrefs prefs) {
     assertEquals("title", prefs.getTitle());
     assertEquals("title_url", prefs.getTitleUrl().toString());
     assertEquals("description", prefs.getDescription());
@@ -67,17 +81,38 @@
     assertFalse(prefs.getScaling());
     assertEquals("category", prefs.getCategories().get(0));
     assertEquals("category2", prefs.getCategories().get(1));
+    assertEquals("author_affiliation", prefs.getAuthorAffiliation());
+    assertEquals("author_location", prefs.getAuthorLocation());
+    assertEquals("author_photo", prefs.getAuthorPhoto());
+    assertEquals("author_aboutme", prefs.getAuthorAboutme());
+    assertEquals("author_quote", prefs.getAuthorQuote());
+    assertEquals(true, prefs.getShowStats());
+    assertEquals(true, prefs.getShowInDirectory());
+    assertEquals(true, prefs.getSingleton());
+
     assertEquals(true, prefs.getFeatures().get("require").getRequired());
     assertEquals(false, prefs.getFeatures().get("optional").getRequired());
+
     assertEquals("http://example.org";,
         prefs.getPreloads().get(0).getHref().toString());
+
     assertEquals(1, prefs.getIcons().size());
+
     assertEquals(1, prefs.getLocales().size());
+
+    assertEquals(URI.create("http://example.org/link";),
+                 prefs.getLinks().get("link").getHref());
   }
 
-  public void testGetAttribute() throws Exception {
-    String xml = "<ModulePrefs title=\"title\" some_attribute=\"attribute\" " +
-        "empty_attribute=\"\"/>";
+  @Test
+  public void basicElementsParseOk() throws Exception {
+    doAsserts(new ModulePrefs(XmlUtil.parse(FULL_XML), SPEC_URL));
+  }
+
+  @Test
+  public void getAttribute() throws Exception {
+    String xml = "<ModulePrefs title='title' some_attribute='attribute' " +
+        "empty_attribute=''/>";
     ModulePrefs prefs = new ModulePrefs(XmlUtil.parse(xml), SPEC_URL);
     assertEquals("title", prefs.getAttribute("title"));
     assertEquals("attribute", prefs.getAttribute("some_attribute"));
@@ -85,10 +120,11 @@
     assertNull(prefs.getAttribute("gobbledygook"));
   }
 
-  public void testGetLocale() throws Exception {
-    String xml = "<ModulePrefs title=\"locales\">" +
-                 "  <Locale lang=\"en\" messages=\"en.xml\"/>" +
-                 "  <Locale lang=\"foo\" language_direction=\"rtl\"/>" +
+  @Test
+  public void getLocale() throws Exception {
+    String xml = "<ModulePrefs title='locales'>" +
+                 "  <Locale lang='en' messages='en.xml'/>" +
+                 "  <Locale lang='foo' language_direction='rtl'/>" +
                  "</ModulePrefs>";
     ModulePrefs prefs = new ModulePrefs(XmlUtil.parse(xml), SPEC_URL);
     LocaleSpec spec = prefs.getLocale(new Locale("en", "uk"));
@@ -98,23 +134,58 @@
     assertEquals("rtl", spec.getLanguageDirection());
   }
 
-  public void testSubstitutions() throws Exception {
-    String xml = "<ModulePrefs title=\"__MSG_title__\"/>";
+  @Test
+  public void getLinks() throws Exception {
+    String link1Rel = "foo";
+    String link2Rel = "bar";
+    URI link1Href = URI.create("http://example.org/foo";);
+    URI link2Href = URI.create("http://example.org/bar";);
+    String xml = "<ModulePrefs title='links'>" +
+                 "  <Link rel='" + link1Rel + "' href='" + link1Href + "'/>" +
+                 "  <Link rel='" + link2Rel + "' href='" + link2Href + "'/>" +
+                 "</ModulePrefs>";
+
+    ModulePrefs prefs = new ModulePrefs(XmlUtil.parse(xml), SPEC_URL);
+
+    assertEquals(link1Href, prefs.getLinks().get(link1Rel).getHref());
+    assertEquals(link2Href, prefs.getLinks().get(link2Rel).getHref());
+  }
+
+  @Test
+  public void doSubstitution() throws Exception {
+    String xml = "<ModulePrefs title='__MSG_title__'>" +
+                 "  <Preload href='http://example.org' authz='signed'/>" +
+                 "  <Icon>__MSG_icon__</Icon>" +
+                 "  <Link rel='__MSG_rel__' href='__MSG_href__'/>" +
+                 "</ModulePrefs>";
     String title = "blah";
+    String icon = "http://example.org/icon.gif";;
+    String rel = "foo-bar";
+    String href = "http://example.org/link.html";;
+
+    ModulePrefs prefs = new ModulePrefs(XmlUtil.parse(xml), SPEC_URL);
     Substitutions substitutions = new Substitutions();
     substitutions.addSubstitution(Substitutions.Type.MESSAGE, "title", title);
-    ModulePrefs prefs = new ModulePrefs(XmlUtil.parse(xml), SPEC_URL);
+    substitutions.addSubstitution(Substitutions.Type.MESSAGE, "icon", icon);
+    substitutions.addSubstitution(Substitutions.Type.MESSAGE, "rel", rel);
+    substitutions.addSubstitution(Substitutions.Type.MESSAGE, "href", href);
     prefs = prefs.substitute(substitutions);
+
     assertEquals(title, prefs.getTitle());
+    assertEquals(icon, prefs.getIcons().get(0).getContent());
+    assertEquals(rel, prefs.getLinks().get(rel).getRel());
+    assertEquals(href, prefs.getLinks().get(rel).getHref().toString());
   }
 
-  public void testTitleRequired() throws Exception {
+  @Test(expected = SpecParserException.class)
+  public void missingTitleThrows() throws Exception {
     String xml = "<ModulePrefs/>";
-    try {
-      ModulePrefs prefs = new ModulePrefs(XmlUtil.parse(xml), SPEC_URL);
-      fail("No exception thrown when [EMAIL PROTECTED] is missing.");
-    } catch (SpecParserException e) {
-      // OK
-    }
+    new ModulePrefs(XmlUtil.parse(xml), SPEC_URL);
+  }
+
+  @Test
+  public void toStringIsSane() throws Exception {
+    ModulePrefs prefs = new ModulePrefs(XmlUtil.parse(FULL_XML), SPEC_URL);
+    doAsserts(new ModulePrefs(XmlUtil.parse(prefs.toString()), SPEC_URL));
   }
 }


Reply via email to