Return-Path: Delivered-To: apmail-incubator-abdera-commits-archive@locus.apache.org Received: (qmail 47887 invoked from network); 21 Aug 2007 00:52:08 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 21 Aug 2007 00:52:08 -0000 Received: (qmail 18717 invoked by uid 500); 21 Aug 2007 00:52:05 -0000 Delivered-To: apmail-incubator-abdera-commits-archive@incubator.apache.org Received: (qmail 18705 invoked by uid 500); 21 Aug 2007 00:52:05 -0000 Mailing-List: contact abdera-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: abdera-dev@incubator.apache.org Delivered-To: mailing list abdera-commits@incubator.apache.org Received: (qmail 18696 invoked by uid 99); 21 Aug 2007 00:52:05 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 20 Aug 2007 17:52:05 -0700 X-ASF-Spam-Status: No, hits=-100.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 21 Aug 2007 00:52:33 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 5AE1B1A981F; Mon, 20 Aug 2007 17:51:38 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r567888 [2/4] - in /incubator/abdera/java/trunk: ./ build/ extensions/ extensions/gdata/ extensions/gdata/src/ extensions/gdata/src/main/ extensions/gdata/src/main/java/ extensions/gdata/src/main/java/org/ extensions/gdata/src/main/java/org... Date: Tue, 21 Aug 2007 00:51:29 -0000 To: abdera-commits@incubator.apache.org From: jmsnell@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20070821005138.5AE1B1A981F@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: incubator/abdera/java/trunk/extensions/geo/src/main/java/org/apache/abdera/ext/geo/Polygon.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/geo/src/main/java/org/apache/abdera/ext/geo/Polygon.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/geo/src/main/java/org/apache/abdera/ext/geo/Polygon.java (added) +++ incubator/abdera/java/trunk/extensions/geo/src/main/java/org/apache/abdera/ext/geo/Polygon.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,78 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.geo; + +public class Polygon + extends Multiple { + + private static final long serialVersionUID = 5387230171535985909L; + + public Polygon() { + super(); + } + + public Polygon(Multiple multiple) { + super(multiple); + verify(); + } + + public Polygon(Point point) { + super(point); + verify(); + } + + public Polygon(Coordinate... coordinates) { + super(coordinates); + verify(); + } + + public Polygon(Coordinates coordinates) { + super(coordinates); + verify(); + } + + public Polygon(String value) { + super(value); + verify(); + } + + public Polygon(Multiple... multiples) { + super(multiples); + verify(); + } + + public Polygon(Point... points) { + super(points); + verify(); + } + + public Polygon(double... values) { + super(values); + verify(); + } + + @Override + public void setCoordinates(Coordinates coordinates) { + super.setCoordinates(coordinates); + verify(); + } + + public void verify() { + super.verify179Rule(); + } +} Added: incubator/abdera/java/trunk/extensions/geo/src/main/java/org/apache/abdera/ext/geo/Position.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/geo/src/main/java/org/apache/abdera/ext/geo/Position.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/geo/src/main/java/org/apache/abdera/ext/geo/Position.java (added) +++ incubator/abdera/java/trunk/extensions/geo/src/main/java/org/apache/abdera/ext/geo/Position.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,132 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.geo; + +import java.io.Serializable; + +public abstract class Position + implements Serializable, + Cloneable, + Comparable { + + public static final String DEFAULT_FEATURE_TYPE_TAG = "location"; + public static final String DEFAULT_RELATIONSHIP_TAG = "is-located-at"; + + protected String featureTypeTag; + protected String relationshipTag; + protected Double elevation; + protected Double floor; + protected Double radius; + + public Double getElevation() { + return elevation; + } + public void setElevation(Double elevation) { + this.elevation = elevation; + } + public String getFeatureTypeTag() { + return featureTypeTag; + } + public void setFeatureTypeTag(String featureTypeTag) { + this.featureTypeTag = featureTypeTag; + } + public Double getFloor() { + return floor; + } + public void setFloor(Double floor) { + this.floor = floor; + } + public Double getRadius() { + return radius; + } + public void setRadius(Double radius) { + this.radius = radius; + } + public String getRelationshipTag() { + return relationshipTag; + } + public void setRelationshipTag(String relationshipTag) { + this.relationshipTag = relationshipTag; + } + + @Override + public int hashCode() { + final int PRIME = 31; + //int result = super.hashCode(); + int result = this.getClass().hashCode(); + result = PRIME * result + ((elevation == null) ? 0 : elevation.hashCode()); + result = PRIME * result + ((featureTypeTag == null) ? DEFAULT_FEATURE_TYPE_TAG.hashCode() : featureTypeTag.hashCode()); + result = PRIME * result + ((floor == null) ? 0 : floor.hashCode()); + result = PRIME * result + ((radius == null) ? 0 : radius.hashCode()); + result = PRIME * result + ((relationshipTag == null) ? DEFAULT_RELATIONSHIP_TAG.hashCode() : relationshipTag.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (getClass() != obj.getClass()) + return false; + final Position other = (Position) obj; + if (elevation == null) { + if (other.elevation != null) + return false; + } else if (!elevation.equals(other.elevation)) + return false; + if (featureTypeTag == null) { + if (other.featureTypeTag != null && + !other.featureTypeTag.equalsIgnoreCase(DEFAULT_FEATURE_TYPE_TAG)) + return false; + } else { + String s = other.featureTypeTag != null ? + other.featureTypeTag : DEFAULT_FEATURE_TYPE_TAG; + if (!featureTypeTag.equalsIgnoreCase(s)) + return false; + } + if (floor == null) { + if (other.floor != null) + return false; + } else if (!floor.equals(other.floor)) + return false; + if (radius == null) { + if (other.radius != null) + return false; + } else if (!radius.equals(other.radius)) + return false; + if (relationshipTag == null) { + if (other.relationshipTag != null && + !other.relationshipTag.equalsIgnoreCase(DEFAULT_RELATIONSHIP_TAG)) + return false; + } else { + String s = other.relationshipTag != null ? + other.relationshipTag : DEFAULT_RELATIONSHIP_TAG; + if (!relationshipTag.equalsIgnoreCase(s)) + return false; + } + return true; + } + + @SuppressWarnings("unchecked") + public T clone() { + try { + return (T)super.clone(); + } catch (CloneNotSupportedException e) { + return null; // should never happen + } + } +} Added: incubator/abdera/java/trunk/extensions/json/pom.xml URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/json/pom.xml?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/json/pom.xml (added) +++ incubator/abdera/java/trunk/extensions/json/pom.xml Mon Aug 20 17:51:20 2007 @@ -0,0 +1,92 @@ + + + + + org.apache.abdera + abdera + 0.3.0-incubating-SNAPSHOT + + 4.0.0 + abdera-extensions-json + jar + Abdera Extensions - JSON + 0.3.0-incubating-SNAPSHOT + Atom Specification Extensions - JSON + 2006 + http://incubator.apache.org/abdera + + scm:svn:http://svn.apache.org/repos/asf/incubator/abdera/java/trunk/extensions/json + scm:svn:https://svn.apache.org/repos/asf/incubator/abdera/java/trunk/extensions/json + http://svn.apache.org/repos/asf/incubator/abdera/java/trunk/extensions/json + + + + org.apache.abdera + abdera-core + 0.3.0-incubating-SNAPSHOT + compile + + + org.apache.abdera + abdera-parser + 0.3.0-incubating-SNAPSHOT + compile + + + org.apache.abdera + abdera-protocol + 0.3.0-incubating-SNAPSHOT + compile + + + org.apache.abdera + abdera-client + 0.3.0-incubating-SNAPSHOT + compile + + + org.apache.abdera + json + 1.0 + compile + + + org.apache.ws.commons.axiom + axiom-api + + + org.apache.ws.commons.axiom + axiom-impl + + + stax + stax-api + + + org.codehaus.woodstox + wstx-asl + + + junit + junit + + + Added: incubator/abdera/java/trunk/extensions/json/src/main/java/org/apache/abdera/ext/json/JSONWriter.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/json/src/main/java/org/apache/abdera/ext/json/JSONWriter.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/json/src/main/java/org/apache/abdera/ext/json/JSONWriter.java (added) +++ incubator/abdera/java/trunk/extensions/json/src/main/java/org/apache/abdera/ext/json/JSONWriter.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,298 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. 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. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ + +package org.apache.abdera.ext.json; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +import org.apache.abdera.model.Base; +import org.apache.abdera.model.Category; +import org.apache.abdera.model.Collection; +import org.apache.abdera.model.Content; +import org.apache.abdera.model.Document; +import org.apache.abdera.model.Entry; +import org.apache.abdera.model.Feed; +import org.apache.abdera.model.Generator; +import org.apache.abdera.model.Link; +import org.apache.abdera.model.Person; +import org.apache.abdera.model.Service; +import org.apache.abdera.model.Workspace; +import org.apache.abdera.model.Content.Type; +import org.apache.abdera.util.AbstractNamedWriter; +import org.apache.abdera.util.AbstractWriterOptions; +import org.apache.abdera.writer.NamedWriter; +import org.apache.abdera.writer.WriterOptions; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class JSONWriter + extends AbstractNamedWriter + implements NamedWriter { + + public static final String NAME = "json"; + + public static final String[] FORMATS = { + "application/json", + "application/javascript", + "application/ecmascript", + "text/javascript", + "text/ecmascript" + }; + + public JSONWriter() { + super(NAME,FORMATS); + } + + public String getName() { + return NAME; + } + + public Object write(Base base, WriterOptions options) throws IOException { + try { + return toJSON(base).toString(); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + public void writeTo(Base base, OutputStream out, WriterOptions options) throws IOException { + try { + Object result = toJSON(base); + out.write(result.toString().getBytes()); + if (options.getAutoClose()) out.close(); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + public void writeTo(Base base, java.io.Writer out, WriterOptions options) throws IOException { + try { + Object result = toJSON(base); + out.write(result.toString()); + if (options.getAutoClose()) out.close(); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + public static Object toJSON(Object object) throws Exception { + if (object instanceof Feed) { + return toJSON((Feed) object); + } else if (object instanceof Entry) { + return toJSON((Entry) object); + } else if (object instanceof Service) { + return toJSON((Service) object); + } else if (object instanceof Document) { + return toJSON(((Document) object).getRoot()); + } + return new IllegalArgumentException("Element is not supported by JSONWriter."); + } + + public static JSONObject toJSON(Entry entry) throws Exception { + JSONObject jsentry = new JSONObject(); + if (entry.getTitle() != null) + jsentry.put("title", entry.getTitle()); + + if (entry.getSummary() != null) + jsentry.put("summary", entry.getSummary()); + + if (entry.getId() != null) + jsentry.put("id", entry.getId().toString()); + + if (entry.getUpdated() != null) + jsentry.put("updated", entry.getUpdated().toString()); + + if (entry.getPublished() != null) + jsentry.put("published", entry.getPublished().toString()); + + jsentry.put("authors", personsToJSON(entry.getAuthors())); + + jsentry.put("contributors", personsToJSON(entry.getContributors())); + + jsentry.put("categories", categoriesToJSON(entry.getCategories())); + + jsentry.put("links", linksToJSON(entry.getLinks())); + + JSONObject jscontent = new JSONObject(); + if (entry.getContentElement() != null) { + + Content content = entry.getContentElement(); + Type type = entry.getContentType(); + if (type.equals(Content.Type.HTML) || type.equals(Content.Type.XHTML) || type.equals(Content.Type.TEXT)) { + jscontent.put("type", type.toString().toLowerCase()); + } else { + jscontent.put("type", content.getMimeType().toString()); + } + jscontent.put("value", content.getValue());; + jsentry.put("content", jscontent); + } + + return jsentry; + } + + public static JSONObject toJSON(Feed feed) throws Exception { + JSONObject jsfeed = new JSONObject(); + + if (feed.getGenerator() != null) { + Generator gen = feed.getGenerator(); + JSONObject jsgen = new JSONObject(); + jsgen.put("uri", gen.getUri().toString()); + jsgen.put("value", gen.getText()); + } + + if (feed.getTitle() != null) { + jsfeed.put("title", feed.getTitle()); + } + + if (feed.getSubtitle() != null) { + jsfeed.put("subtitle", feed.getSubtitle()); + } + + if (feed.getId() != null) { + jsfeed.put("id", feed.getId().toString()); + } + + if (feed.getRights() != null) { + jsfeed.put("rights", feed.getRights()); + } + + if (feed.getLogo() != null) { + jsfeed.put("logo", feed.getLogo().toString()); + } + + if (feed.getIcon() != null) { + jsfeed.put("icon", feed.getIcon().toString()); + } + + if (feed.getUpdatedString() != null) { + jsfeed.put("updated", feed.getUpdatedString()); + } + + jsfeed.put("authors", personsToJSON(feed.getAuthors())); + + jsfeed.put("contributors", personsToJSON(feed.getContributors())); + + jsfeed.put("categories", categoriesToJSON(feed.getCategories())); + + jsfeed.put("links", linksToJSON(feed.getLinks())); + + JSONArray jsentries = new JSONArray(); + List entries = feed.getEntries(); + for (Entry entry : entries) { + jsentries.put(toJSON(entry)); + } + + jsfeed.put("entries", jsentries); + + return jsfeed; + } + + public static JSONObject toJSON(Service service) throws Exception { + JSONObject jssvc = new JSONObject(); + JSONArray jsworkspaces = new JSONArray(); + List workspaces = service.getWorkspaces(); + for (Workspace workspace : workspaces) { + JSONObject jsworkspace = new JSONObject(); + JSONArray jscollections = new JSONArray(); + jsworkspace.put("title", workspace.getTitle()); + List collections = workspace.getCollections(); + for (Collection collection : collections) { + JSONObject jscollection = new JSONObject(); + JSONArray jsaccepts = new JSONArray(); + String[] accepts = collection.getAccept(); + for (String accept : accepts) { + jsaccepts.put(accept); + } + jscollection.put("href", collection.getHref().toString()); + jscollection.put("accept", jsaccepts); + jscollections.put(jscollection); + } + jsworkspace.put("collections", jscollections); + jsworkspaces.put(jsworkspace); + } + jssvc.put("workspaces", jsworkspaces); + + return jssvc; + } + + private static JSONArray categoriesToJSON(List categories) throws JSONException { + JSONArray jscategories = new JSONArray(); + for (Category category : categories) { + if (category.getScheme() != null || category.getLabel() != null || category.getTerm() != null) { + JSONObject jscategory = new JSONObject(); + if (category.getScheme() != null) + jscategory.put("scheme", category.getScheme().toString()); + + if (category.getTerm() != null) + jscategory.put("term", category.getTerm()); + + if (category.getLabel() != null) + jscategory.put("label", category.getLabel()); + jscategories.put(jscategory); + } + } + return jscategories; + } + + private static JSONArray personsToJSON(List persons) throws JSONException { + JSONArray jspersons = new JSONArray(); + for (Person p : persons) { + if (p.getName() != null || p.getUri() != null || p.getEmail() != null) { + JSONObject jsperson = new JSONObject(); + if (p.getName() != null) + jsperson.put("name", p.getName()); + if (p.getUri() != null) + jsperson.put("uri", p.getUri().toString()); + if (p.getEmail() != null) + jsperson.put("email", p.getEmail()); + jspersons.put(jsperson); + } + } + return jspersons; + } + + private static JSONArray linksToJSON(List links) throws JSONException { + JSONArray jslinks = new JSONArray(); + for (Link link : links) { + JSONObject jslink = new JSONObject(); + if (link.getHref() != null) { + jslink.put("href", link.getHref().toString()); + + if (link.getRel() != null) + jslink.put("rel", link.getRel()); + + if (link.getMimeType() != null) + jslink.put("type", link.getMimeType().getBaseType()); + + if (link.getHrefLang() != null) + jslink.put("hreflang", link.getHrefLang()); + } + jslinks.put(jslink); + } + return jslinks; + } + + @Override + protected WriterOptions initDefaultWriterOptions() { + return new AbstractWriterOptions() {}; + } + +} Added: incubator/abdera/java/trunk/extensions/json/src/main/resources/META-INF/services/org.apache.abdera.writer.NamedWriter URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/json/src/main/resources/META-INF/services/org.apache.abdera.writer.NamedWriter?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/json/src/main/resources/META-INF/services/org.apache.abdera.writer.NamedWriter (added) +++ incubator/abdera/java/trunk/extensions/json/src/main/resources/META-INF/services/org.apache.abdera.writer.NamedWriter Mon Aug 20 17:51:20 2007 @@ -0,0 +1 @@ +org.apache.abdera.ext.json.JSONWriter \ No newline at end of file Added: incubator/abdera/java/trunk/extensions/main/pom.xml URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/pom.xml?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/pom.xml (added) +++ incubator/abdera/java/trunk/extensions/main/pom.xml Mon Aug 20 17:51:20 2007 @@ -0,0 +1,92 @@ + + + + + org.apache.abdera + abdera + 0.3.0-incubating-SNAPSHOT + + 4.0.0 + abdera-extensions-main + jar + Abdera Extensions - Main + 0.3.0-incubating-SNAPSHOT + Atom Specification Extensions - Main + 2006 + http://incubator.apache.org/abdera + + scm:svn:http://svn.apache.org/repos/asf/incubator/abdera/java/trunk/extensions/main + scm:svn:https://svn.apache.org/repos/asf/incubator/abdera/java/trunk/extensions/main + http://svn.apache.org/repos/asf/incubator/abdera/java/trunk/extensions/main + + + + org.apache.abdera + abdera-core + 0.3.0-incubating-SNAPSHOT + compile + + + org.apache.abdera + abdera-parser + 0.3.0-incubating-SNAPSHOT + compile + + + org.apache.abdera + abdera-protocol + 0.3.0-incubating-SNAPSHOT + compile + + + org.apache.abdera + abdera-client + 0.3.0-incubating-SNAPSHOT + compile + + + org.apache.abdera + json + 1.0 + compile + + + org.apache.ws.commons.axiom + axiom-api + + + org.apache.ws.commons.axiom + axiom-impl + + + stax + stax-api + + + org.codehaus.woodstox + wstx-asl + + + junit + junit + + + Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/bidi/BidiHelper.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/bidi/BidiHelper.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/bidi/BidiHelper.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/bidi/BidiHelper.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,308 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.bidi; + +import java.text.AttributedString; +import java.text.Bidi; +import java.util.Locale; + +import javax.xml.namespace.QName; + +import org.apache.abdera.model.Base; +import org.apache.abdera.model.Element; +import org.apache.abdera.i18n.io.CharUtils; +import org.apache.abdera.i18n.lang.Lang; + +/** + *

This is (hopefully) temporary. Ideally, this would be wrapped into the + * core model API so that the bidi stuff is handled seamlessly. There are + * still details being worked out on the Atom WG list and it's likely that + * at least one other impl (mozilla) will do something slightly different.

+ * + *

Based on http://www.ietf.org/internet-drafts/draft-snell-atompub-bidi-04.txt

+ * + *

Example:

+ *
+ *   <feed xmlns="http://www.w3.org/2005/Atom" dir="rtl">
+ *     ...
+ *   </feed>
+ * 
+ * + *

The getBidi___ elements use the in-scope direction to wrap the text with + * the appropriate Unicode control characters. e.g. if dir="rtl", the text is + * wrapped with the RLE and PDF controls. If the text already contains the + * control chars, the dir attribute is ignored.

+ * + *
+ *    org.apache.abdera.Abdera abdera = new org.apache.abdera.Abdera();
+ *    org.apache.abdera.model.Feed feed = abdera.getFactory().newFeed();
+ *    feed.setAttributeValue("dir", "rtl");
+ *    feed.setTitle("Testing");
+ *    feed.addCategory("foo");
+ *    
+ *    System.out.println(
+ *      BidiHelper.getBidiElementText(
+ *        feed.getTitleElement()));
+ *    System.out.println(
+ *      BidiHelper.getBidiAttributeValue(
+ *        feed.getCategories().get(0),"term"));
+ * 
+ * + */ +public final class BidiHelper { + + private static final QName DIR = new QName("dir"); + + BidiHelper() {} + + public enum Direction { UNSPECIFIED, LTR, RTL}; + + /** + * Set the value of dir attribute + */ + public static void setDirection( + Direction direction, + T element) { + if (direction != Direction.UNSPECIFIED) + element.setAttributeValue( + DIR, + direction.toString().toLowerCase()); + else if (direction == Direction.UNSPECIFIED) + element.setAttributeValue(DIR,""); + else if (direction == null) + element.removeAttribute(DIR); + } + + /** + * Get the in-scope direction for an element. + */ + public static Direction getDirection(T element) { + Direction direction = Direction.UNSPECIFIED; + String dir = element.getAttributeValue("dir"); + if (dir != null && dir.length() > 0) + direction = Direction.valueOf(dir.toUpperCase()); + else if (dir == null) { + // if the direction is unspecified on this element, + // let's see if we've inherited it + Base parent = element.getParentElement(); + if (parent != null && + parent instanceof Element) + direction = getDirection((Element)parent); + } + return direction; + } + + /** + * Return the specified text with appropriate Unicode Control Characters given + * the specified Direction. + * @param direction The Directionality of the text + * @param text The text to wrap within Unicode Control Characters + * @return The directionally-wrapped text + */ + public static String getBidiText(Direction direction, String text) { + switch (direction) { + case LTR: return CharUtils.bidiLRE(text); + case RTL: return CharUtils.bidiRLE(text); + default: return text; + } + } + + /** + * Return the textual content of a child element using the in-scope directionality + * @param element The parent element + * @param child The XML QName of the child element + * @return The directionally-wrapped text of the child element + */ + public static String getBidiChildText(T element, QName child) { + Element el = element.getFirstChild(child); + return (el != null) ? getBidiText(getDirection(el),el.getText()) : null; + } + + /** + * Return the textual content of the specified element + * @param element An element containing directionally-sensitive text + * @return The directionally-wrapped text of the element + */ + public static String getBidiElementText(T element) { + return getBidiText(getDirection(element),element.getText()); + } + + /** + * Return the text content of the specified attribute using the in-scope directionality + * @param element The parent element + * @param name the name of the attribute + * @return The directionally-wrapped text of the attribute + */ + public static String getBidiAttributeValue(T element, String name) { + return getBidiText(getDirection(element),element.getAttributeValue(name)); + } + + /** + * Return the text content of the specified attribute using the in-scope directionality + * @param element The parent element + * @param name the name of the attribute + * @return The directionally-wrapped text of the attribute + */ + public static String getBidiAttributeValue(T element, QName name) { + return getBidiText(getDirection(element),element.getAttributeValue(name)); + } + + + /** + * Attempt to guess the base direction using the in-scope language. + * Implements the method used by Internet Explorer 7's feed view + * documented here: http://blogs.msdn.com/rssteam/archive/2007/05/17/reading-feeds-in-right-to-left-order.aspx. + * + * This algorithm differs slightly from the method documented in that the + * primary language tag is case insensitive. + * + * If the language tag is not specified, then the default Locale is used to + * determine the direction. + * + * If the dir attribute is specified, the direction will be determine using it's value + * instead of the language + */ + public static Direction guessDirectionFromLanguage(T element) { + return guessDirectionFromLanguage(element, false); + } + + /** + * Attempt to guess the base direction using the in-scope language. + * Implements the method used by Internet Explorer 7's feed view + * documented here: http://blogs.msdn.com/rssteam/archive/2007/05/17/reading-feeds-in-right-to-left-order.aspx. + * + * This algorithm differs slightly from the method documented in that the + * primary language tag is case insensitive. + * + * If the language tag is not specified, then the default Locale is used to + * determine the direction. + * + * According to the Atom Bidi spec, if the dir attribute is set explicitly, we + * should not do language guessing. This restriction can be bypassed by setting + * ignoredir to true. + */ + public static Direction guessDirectionFromLanguage(T element, boolean ignoredir) { + if (!ignoredir && hasDirection(element)) return getDirection(element); + Lang lang = element.getLanguageTag(); + if (lang == null) { + Locale l = Locale.getDefault(); + lang = new Lang(l.getLanguage()); + } + String primary = lang.getPrimary(); + return (primary.equalsIgnoreCase("ar") || + primary.equalsIgnoreCase("fa") || + primary.equalsIgnoreCase("ur") || + primary.equalsIgnoreCase("ps") || + primary.equalsIgnoreCase("syr") || + primary.equalsIgnoreCase("dv") || + primary.equalsIgnoreCase("he") || + primary.equalsIgnoreCase("yi")) ? Direction.RTL : Direction.LTR; + } + + /** + * Attempt to guess the base direction of an element using an analysis of + * the directional properties of the characters used. This is a brute-force + * style approach that can achieve fairly reasonable results when the element + * text consists primarily of characters with the same bidi properties. This + * approach is implemented by the Snarfer feed reader as is documented at + * http://www.xn--8ws00zhy3a.com/blog/2006/12/right-to-left-rss + * + * If the dir attribute is specified, the direction will be determine using it's value + * instead of the characteristics of the text + */ + public static Direction guessDirectionFromTextProperties(T element) { + return guessDirectionFromTextProperties(element, false); + } + + /** + * Attempt to guess the base direction of an element using an analysis of + * the directional properties of the characters used. This is a brute-force + * style approach that can achieve fairly reasonable results when the element + * text consists primarily of characters with the same bidi properties. This + * approach is implemented by the Snarfer feed reader as is documented at + * http://www.xn--8ws00zhy3a.com/blog/2006/12/right-to-left-rss + * + * According to the Atom Bidi spec, if the dir attribute is set explicitly, we + * should not do language guessing. This restriction can be bypassed by setting + * ignoredir to true. + */ + public static Direction guessDirectionFromTextProperties(T element, boolean ignoredir) { + Direction dir = Direction.UNSPECIFIED; + if (!ignoredir && hasDirection(element)) return getDirection(element); + String text = element.getText(); + if (text != null) { + int c = 0; + for (int n = 0; n < text.length(); n++) { + char ch = text.charAt(n); + if (Bidi.requiresBidi(new char[] {ch}, 0, 1)) c++; + else c--; + } + dir = (c > 0) ? Direction.RTL : Direction.LTR; + } + return dir; + } + + /** + * Use Java's built in support for bidi text to determine the base directionality + * of the element's text. The response to this only indicates the *base* directionality, + * it does not indicate whether or not there are any RTL characters in the text. + * + * If the dir attribute is specified, the direction will be determine using it's value + * instead of the characteristics of the text + */ + public static Direction guessDirectionFromJavaBidi(T element) { + return guessDirectionFromJavaBidi(element, false); + } + + /** + * Use Java's built in support for bidi text to determine the base directionality + * of the element's text. The response to this only indicates the *base* directionality, + * it does not indicate whether or not there are any RTL characters in the text. + * + * According to the Atom Bidi spec, if the dir attribute is set explicitly, we + * should not do language guessing. This restriction can be bypassed by setting + * ignoredir to true. + */ + public static Direction guessDirectionFromJavaBidi(T element, boolean ignoredir) { + Direction dir = Direction.UNSPECIFIED; + if (!ignoredir && hasDirection(element)) return getDirection(element); + String text = element.getText(); + if (text != null) { + AttributedString s = new AttributedString(text); + Bidi bidi = new Bidi(s.getIterator()); + dir = (bidi.baseIsLeftToRight()) ? Direction.LTR : Direction.RTL; + } + return dir; + } + + private static boolean hasDirection(T element) { + boolean answer = false; + String dir = element.getAttributeValue("dir"); + if (dir != null && dir.length() > 0) + answer = true; + else if (dir == null) { + // if the direction is unspecified on this element, + // let's see if we've inherited it + Base parent = element.getParentElement(); + if (parent != null && + parent instanceof Element) + answer = hasDirection((Element)parent); + } + return answer; + } +} Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/AbstractSelector.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/AbstractSelector.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/AbstractSelector.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/AbstractSelector.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,36 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.features; + +public abstract class AbstractSelector + implements Selector { + + public Selector clone() { + try { + return (Selector) super.clone(); + } catch (CloneNotSupportedException e) { + return copy(); + } + } + + protected Selector copy() { + throw new RuntimeException( + new CloneNotSupportedException()); + } + +} Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/AcceptSelector.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/AcceptSelector.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/AcceptSelector.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/AcceptSelector.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,43 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.features; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.abdera.model.Collection; + +public class AcceptSelector + extends AbstractSelector + implements Selector { + + private static final long serialVersionUID = -1289924342084041384L; + private final List accepts = new ArrayList(); + + public AcceptSelector(String... accepts) { + for (String accept : accepts) this.accepts.add(accept); + } + + public boolean select(Collection collection) { + for (String accept : accepts) { + if (collection.accepts(accept)) return true; + } + return false; + } + +} Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/Feature.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/Feature.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/Feature.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/Feature.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,96 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.features; + +import javax.xml.namespace.QName; + +import org.apache.abdera.factory.Factory; +import org.apache.abdera.i18n.iri.IRI; +import org.apache.abdera.model.Element; +import org.apache.abdera.model.ExtensibleElementWrapper; + +public class Feature + extends ExtensibleElementWrapper { + + public enum Status { + UNSUPPORTED, + UNSPECIFIED, + SUPPORTED, + REQUIRED, + } + + public Feature(Element internal) { + super(internal); + } + + public Feature(Factory factory) { + super(factory, FeaturesHelper.FEATURE); + } + + public IRI getRef() { + String ref = getAttributeValue("ref"); + return (ref != null) ? new IRI(ref) : null; + } + + public Status getStatus() { + String status = getAttributeValue("status"); + return status != null ? Status.valueOf(status.toUpperCase()) : Status.SUPPORTED; + } + + public void setStatus(Status status) { + if (status != null && status != Status.SUPPORTED) { + if (status != Status.UNSPECIFIED) { + setAttributeValue("status",status.name().toLowerCase()); + } else { + throw new IllegalArgumentException( + "Cannot set the status to unspecified"); + } + } else { + removeAttribute(new QName("status")); + } + } + + public IRI getHref() { + String href = getAttributeValue("href"); + return (href != null) ? new IRI(href) : null; + } + + public String getLabel() { + return getAttributeValue("label"); + } + + public void setRef(String ref) { + if (ref == null) throw new IllegalArgumentException(); + setAttributeValue("ref", (new IRI(ref)).toString()); + } + + public void setHref(String href) { + if (href != null) + setAttributeValue("href", (new IRI(href)).toString()); + else + removeAttribute(new QName("href")); + } + + public void setLabel(String label) { + if (label != null) + setAttributeValue("label", label); + else + removeAttribute(new QName("label")); + } + +} Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeatureSelector.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeatureSelector.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeatureSelector.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeatureSelector.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,84 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.features; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.abdera.ext.features.Feature.Status; +import org.apache.abdera.model.Collection; + +public class FeatureSelector + extends AbstractSelector + implements Selector { + + private static final long serialVersionUID = -8943638085557912175L; + private final Status minimumStatus; + private final List features = new ArrayList(); + + public FeatureSelector(String... features) { + this(Status.SUPPORTED,features); + } + + public FeatureSelector(Status minimumStatus, String... features) { + this.minimumStatus = minimumStatus; + for (String feature : features) this.features.add(feature); + } + + public boolean select(Collection collection) { + for (String feature : features) { + Status status = FeaturesHelper.getFeatureStatus(collection, feature); + if (status != null && status.ordinal() >= minimumStatus.ordinal()) + return true; + } + return false; + } + + public String[] getFeatures() { + return features.toArray(new String[features.size()]); + } + + public Status getMinimumStatus() { + return minimumStatus; + } + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((features == null) ? 0 : features.hashCode()); + result = PRIME * result + ((minimumStatus == null) ? 0 : minimumStatus.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + final FeatureSelector other = (FeatureSelector) obj; + if (features == null) { + if (other.features != null) return false; + } else if (!features.equals(other.features)) return false; + if (minimumStatus == null) { + if (other.minimumStatus != null) return false; + } else if (!minimumStatus.equals(other.minimumStatus)) return false; + return true; + } + +} Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeaturesExtensionFactory.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeaturesExtensionFactory.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeaturesExtensionFactory.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeaturesExtensionFactory.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,30 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.features; + +import org.apache.abdera.util.AbstractExtensionFactory; + +public final class FeaturesExtensionFactory + extends AbstractExtensionFactory { + + public FeaturesExtensionFactory() { + super(FeaturesHelper.FNS); + addImpl(FeaturesHelper.FEATURE,Feature.class); + } + +} Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeaturesHelper.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeaturesHelper.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeaturesHelper.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/FeaturesHelper.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,352 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.features; + +import java.util.ArrayList; +import java.util.List; + +import javax.activation.MimeType; +import javax.activation.MimeTypeParseException; +import javax.xml.namespace.QName; + +import org.apache.abdera.ext.features.Feature.Status; +import org.apache.abdera.ext.thread.ThreadConstants; +import org.apache.abdera.factory.Factory; +import org.apache.abdera.i18n.iri.IRI; +import org.apache.abdera.model.Collection; +import org.apache.abdera.model.Element; +import org.apache.abdera.model.Service; +import org.apache.abdera.model.Workspace; +import org.apache.abdera.util.MimeTypeHelper; + +/** + * Implementation of the current APP Features Draft + * (http://www.ietf.org/internet-drafts/draft-snell-atompub-feature-05.txt) + */ +public final class FeaturesHelper { + + public static final String FNS = "http://purl.org/atompub/features/1.0"; + public static final QName FEATURE = new QName(FNS, "feature","f"); + public static final QName TYPE = new QName(FNS, "type", "f"); + + private static final String FEATURE_BASE = "http://www.w3.org/2007/app/"; + public static final String FEATURE_DRAFTS = FEATURE_BASE + "drafts"; + public static final String FEATURE_XHTML_CONTENT = FEATURE_BASE + "xhtml-content"; + public static final String FEATURE_HTML_CONTENT = FEATURE_BASE + "html-content"; + public static final String FEATURE_TEXT_CONTENT = FEATURE_BASE + "text-content"; + public static final String FEATURE_XML_CONTENT = FEATURE_BASE + "xml-content"; + public static final String FEATURE_BINARY_CONTENT = FEATURE_BASE + "binary-content"; + public static final String FEATURE_REF_CONTENT = FEATURE_BASE + "ref-content"; + public static final String FEATURE_XHTML_TITLE = FEATURE_BASE + "xhtml-title"; + public static final String FEATURE_HTML_TITLE = FEATURE_BASE + "html-title"; + public static final String FEATURE_TEXT_TITLE = FEATURE_BASE + "text-title"; + public static final String FEATURE_XHTML_SUMMARY = FEATURE_BASE + "xhtml-summary"; + public static final String FEATURE_HTML_SUMMARY = FEATURE_BASE + "html-summary"; + public static final String FEATURE_TEXT_SUMMARY = FEATURE_BASE + "text-summary"; + public static final String FEATURE_AUTO_SUMMARY = FEATURE_BASE + "auto-summary"; + public static final String FEATURE_XHTML_RIGHTS = FEATURE_BASE + "xhtml-rights"; + public static final String FEATURE_HTML_RIGHTS = FEATURE_BASE + "html-rights"; + public static final String FEATURE_TEXT_RIGHTS = FEATURE_BASE + "text-rights"; + public static final String FEATURE_AUTH_AUTHOR = FEATURE_BASE + "auth-author"; + public static final String FEATURE_SLUG = FEATURE_BASE + "slug"; + public static final String FEATURE_MULTIPLE_CATEGORIES = FEATURE_BASE + "multiple-categories"; + public static final String FEATURE_MULTIPLE_AUTHORS = FEATURE_BASE + "multiple-authors"; + public static final String FEATURE_MULTIPLE_CONTRIBUTORS = FEATURE_BASE + "multiple-contributors"; + public static final String FEATURE_PRESERVE_INFOSET = FEATURE_BASE + "preserve-infoset"; + public static final String FEATURE_PRESERVE_ID = FEATURE_BASE + "preserve-id"; + public static final String FEATURE_PRESERVE_DATES = FEATURE_BASE + "preserve-dates"; + public static final String FEATURE_PRESERVE_EXTENSIONS = FEATURE_BASE + "preserve-extensions"; + public static final String FEATURE_PRESERVE_LINKS = FEATURE_BASE + "preserve-links"; + public static final String FEATURE_PRESERVE_RIGHTS = FEATURE_BASE + "preserve-rights"; + public static final String FEATURE_SCHEDULED_PUBLISHING = FEATURE_BASE + "scheduled-publishing"; + public static final String FEATURE_THREADING = ThreadConstants.THR_NS; + + + private static final String ABDERA_FEATURE_BASE = "http://incubator.apache.org/abdera/features/"; + + /** + * Indicates that the collection will accept digitally signed entries + * If marked as "required", the collection will only accept digitally signed entries + */ + public static final String ABDERA_FEATURE_SIGNATURE = ABDERA_FEATURE_BASE + "signature"; + + /** + * Indicates that the collection will preserve XML digital signatures contained + * in member resources + */ + public static final String ABDERA_FEATURE_PRESERVE_SIGNATURE = ABDERA_FEATURE_BASE + "preserve-signature"; + + /** + * Indicates that the collection supports the use of the Atom Bidi Attribute. + * If marked as "required", the collection will only accept entries that contain the bidi attribute + */ + public static final String ABDERA_FEATURE_BIDI = ABDERA_FEATURE_BASE + "bidi"; + + /** + * Indicates that the collection supports the use of Diffie-Hellman key exchange + * for XML encrypted requests + */ + public static final String ABDERA_FEATURE_DHENCREQUEST = ABDERA_FEATURE_BASE + "dhenc-request"; + + /** + * Indicates that the collection supports the use of Diffie-Hellman key exchange + * for XML encrypted responses + */ + public static final String ABDERA_FEATURE_DHENCRESPONSE = ABDERA_FEATURE_BASE + "dhenc-response"; + + /** + * Indicates that the collection will add it's own digital signature to the + * collection feed and member resources + */ + public static final String ABDERA_FEATURE_SIGNED_RESPONSE = ABDERA_FEATURE_BASE + "response-signature"; + + /** + * Indicates that the collection supports the use of Geo extensions (see the + * org.apache.abdera.ext.geo Package) + */ + public static final String ABDERA_FEATURE_GEO = ABDERA_FEATURE_BASE + "geo"; + + /** + * Indicates that the collection supports the use of the Feed paging standard. + * (ftp://ftp.rfc-editor.org/in-notes/internet-drafts/draft-nottingham-atompub-feed-history-11.txt) + * See the org.apache.abdera.ext.history Package) + */ + public static final String ABDERA_FEATURE_PAGING = ABDERA_FEATURE_BASE + "paging"; + + /** + * Indicates that the collection supports the use of the Simple Sharing Extensions + * (see the org.apache.abdera.ext.sharing Package) + */ + public static final String ABDERA_FEATURE_SHARING = ABDERA_FEATURE_BASE + "sharing"; + + /** + * Indicates that the collection supports the GoogleLogin auth scheme + * (see the org.apache.abdera.ext.gdata Package) + */ + public static final String ABDERA_FEATURE_GOOGLELOGIN = ABDERA_FEATURE_BASE + "googlelogin"; + + /** + * Indicates that the collection supports the WSSE auth scheme + * (see the org.apache.abdera.ext.wsse Package) + */ + public static final String ABDERA_FEATURE_WSSE = ABDERA_FEATURE_BASE + "wsse"; + + + + + private FeaturesHelper() {} + + /** + * Returns the specified feature element or null + */ + public static Feature getFeature( + Collection collection, + String feature) { + List list = collection.getExtensions(FEATURE); + for (Element el : list) { + if (el.getAttributeValue("ref").equals(feature)) + return (Feature) el; + } + return null; + } + + public static Status getFeatureStatus(Collection collection, String feature) { + Feature f = getFeature(collection,feature); + return f != null ? f.getStatus() : Status.UNSPECIFIED; + } + + public static Feature[] getSupportedFeatures(Collection collection) { + return getFeatures(collection, Status.SUPPORTED); + } + + public static Feature[] getUnsupportedFeatures(Collection collection) { + return getFeatures(collection, Status.UNSUPPORTED); + } + + public static Feature[] getRequiredFeatures(Collection collection) { + return getFeatures(collection, Status.REQUIRED); + } + + public static Feature[] getFeatures(Collection collection, Status status) { + if (status == null) status = Status.SUPPORTED; + List list = new ArrayList(); + List features = collection.getExtensions(FEATURE); + for (Feature feature : features) { + if (status == feature.getStatus()) { + list.add(feature); + } + } + return list.toArray(new Feature[list.size()]); + } + + /** + * Add the specified features to the collection + */ + public static Feature[] addFeatures( + Collection collection, + String... features) { + List list = new ArrayList(); + for (String feature : features) + list.add(addFeature(collection,feature)); + return list.toArray(new Feature[list.size()]); + } + + /** + * Add the specified features to the collection + */ + public static Feature[] addFeatures( + Collection collection, + Status status, + String... features) { + List list = new ArrayList(); + for (String feature : features) + list.add(addFeature(collection,feature, status)); + return list.toArray(new Feature[list.size()]); + } + + /** + * Add the specified feature to the collection + * @param collection The collection + * @param feature The IRI of the feature to add + */ + public static Feature addFeature( + Collection collection, + String feature) { + return addFeature( + collection, + feature, + null, null, null); + } + + /** + * Add the specified feature to the collection + * @param collection The collection + * @param feature The IRI of the feature to add + */ + public static Feature addFeature( + Collection collection, + String feature, + Status status) { + return addFeature( + collection, + feature, + status, + null, null); + } + + /** + * Add the specified feature to the collection + * @param collection The collection + * @param feature The IRI of the feature to add + * @param required True if the feature is required + * @param href An IRI pointing to a human readable resource describing the feature + * @param label A human readable label for the feature + */ + public static Feature addFeature( + Collection collection, + String feature, + Status status, + String href, + String label) { + if (getFeature(collection, feature) != null) + throw new IllegalArgumentException("Feature already specified"); + Factory factory = collection.getFactory(); + Feature el = + (Feature)factory.newExtensionElement( + FeaturesHelper.FEATURE, collection); + collection.declareNS(FNS, "f"); + el.setRef(new IRI(feature).toString()); + el.setStatus(status); + if (href != null) el.setHref(new IRI(href).toString()); + if (label != null) el.setLabel(label); + return el; + } + + /** + * Select a Collection from the service document + */ + public static Collection[] select(Service service, Selector selector) { + return select(service, new Selector[] {selector}); + } + + /** + * Select a Collection from the service document + */ + public static Collection[] select(Service service, Selector... selectors) { + List list = new ArrayList(); + for (Workspace workspace : service.getWorkspaces()) { + Collection[] collections = select(workspace, selectors); + for (Collection collection : collections) + list.add(collection); + } + return list.toArray(new Collection[list.size()]); + } + + /** + * Select a Collection from the Workspace + */ + public static Collection[] select(Workspace workspace, Selector selector) { + return select(workspace, new Selector[] {selector}); + } + + /** + * Select a Collection from the Workspace + */ + public static Collection[] select(Workspace workspace, Selector... selectors) { + List list = new ArrayList(); + for (Collection collection : workspace.getCollections()) { + boolean accept = true; + for (Selector selector : selectors) { + if (!selector.select(collection)) { + accept = false; + break; + } + } + if (accept) list.add(collection); + } + return list.toArray(new Collection[list.size()]); + } + + public static void addType(Feature feature, String mediaRange) { + addType(feature, new String[] {mediaRange}); + } + + public static void addType(Feature feature, String... mediaRanges) { + mediaRanges = MimeTypeHelper.condense(mediaRanges); + for (String mediaRange : mediaRanges) { + try { + feature.addSimpleExtension(TYPE, new MimeType(mediaRange).toString()); + } catch (MimeTypeParseException e) {} + } + } + + public static String[] getTypes(Feature feature) { + List list = new ArrayList(); + for (Element type : feature.getExtensions(TYPE)) { + String value = type.getText(); + if (value != null) { + value = value.trim(); + try { + list.add(new MimeType(value).toString()); + } catch (MimeTypeParseException e) {} + } + } + return list.toArray(new String[list.size()]); + } + +} Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/Selector.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/Selector.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/Selector.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/Selector.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,31 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.features; + +import java.io.Serializable; + +import org.apache.abdera.model.Collection; + +public interface Selector + extends Cloneable, Serializable { + + boolean select(Collection collection); + + Selector clone(); + +} Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/XPathSelector.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/XPathSelector.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/XPathSelector.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/features/XPathSelector.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,89 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.features; + +import java.util.Map; + +import org.apache.abdera.Abdera; +import org.apache.abdera.model.Collection; +import org.apache.abdera.xpath.XPath; + +/** + * Selects a collection based on a boolean XPath expression + */ +public class XPathSelector + extends AbstractSelector + implements Selector { + + private static final long serialVersionUID = 7751803876821166591L; + + private final XPath xpath; + private final Map namespaces; + private final String path; + + public XPathSelector( + String path) { + this(path,(new Abdera()).getXPath()); + } + + public XPathSelector( + String path, + XPath xpath) { + this(path,xpath,xpath.getDefaultNamespaces()); + } + + public XPathSelector( + String path, + XPath xpath, + Map namespaces) { + this.path = path; + this.xpath = xpath; + this.namespaces = namespaces; + if (!this.namespaces.containsValue(FeaturesHelper.FNS)) { + int c = 0; + String p = "f"; + if (!this.namespaces.containsKey(p)) { + this.namespaces.put(p, FeaturesHelper.FNS); + } else { + String s = p + c; + while (this.namespaces.containsKey(s)) { + c++; s = p + c; + } + this.namespaces.put(s, FeaturesHelper.FNS); + } + } + } + + public String getFeaturesPrefix() { + for (Map.Entry entry : namespaces.entrySet()) { + if (entry.getValue().equals(FeaturesHelper.FNS)) return entry.getKey(); + } + return null; + } + + public boolean select(Collection collection) { + if (xpath.booleanValueOf(path, collection, namespaces)) { + return true; + } + return false; + } + + public void addNamespace(String prefix, String uri) { + namespaces.put(prefix, uri); + } +} Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/history/FeedPagingHelper.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/history/FeedPagingHelper.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/history/FeedPagingHelper.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/history/FeedPagingHelper.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,289 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.history; + +import javax.xml.namespace.QName; + +import org.apache.abdera.model.Element; +import org.apache.abdera.model.Feed; +import org.apache.abdera.model.Link; +import org.apache.abdera.i18n.iri.IRI; + +/** + * Initial support for Mark Nottingham's Feed Paging and Archiving draft + * (http://ietfreport.isoc.org/all-ids/draft-nottingham-atompub-feed-history-11.txt) + */ +public final class FeedPagingHelper { + + public static final String FH_PREFIX = "fh"; + public static final String FHNS = "http://purl.org/syndication/history/1.0"; + public static final QName COMPLETE = new QName(FHNS, "complete", FH_PREFIX); + public static final QName ARCHIVE = new QName(FHNS, "archive", FH_PREFIX); + + FeedPagingHelper() {} + + /** + * Returns true if the feed is "complete". According to the Feed Paging + * and Archiving specification, in a complete feed, "any entry not actually + * in the feed document SHOULD NOT be considered to be part of that feed." + * @param feed The feed to check + */ + public static boolean isComplete(Feed feed) { + return (feed.getExtension(COMPLETE) != null); + } + + /** + * Flag the feed as being complete. According to the Feed Paging + * and Archiving specification, in a complete feed, "any entry not actually + * in the feed document SHOULD NOT be considered to be part of that feed." + * @param feed The Feed to mark as complete + * @param complete True if the feed is complete + */ + public static void setComplete(Feed feed, boolean complete) { + if (complete) { + if (!isComplete(feed)) feed.addExtension(COMPLETE); + } else { + if (isComplete(feed)) { + Element ext = feed.getExtension(COMPLETE); + ext.discard(); + } + } + } + + /** + * Flag the feed as being an archive. + * @param feed The Feed to mark as an archive + * @param archive True if the feed is an archive + */ + public static void setArchive(Feed feed, boolean archive) { + if (archive) { + if (!isArchive(feed)) feed.addExtension(ARCHIVE); + } else { + if (isArchive(feed)) { + Element ext = feed.getExtension(ARCHIVE); + ext.discard(); + } + } + } + + /** + * Return true if the feed has been marked as an archive + * @param feed The feed to check + */ + public static boolean isArchive(Feed feed) { + return feed.getExtension(ARCHIVE) != null; + } + + /** + * Return true if the feed contains any next, previous, first or last + * paging link relations + * @param feed The feed to check + */ + public static boolean isPaged(Feed feed) { + return feed.getLink("next") != null || + feed.getLink("previous") != null || + feed.getLink("first") != null || + feed.getLink("last") != null; + } + + /** + * Adds a next link relation to the feed + * @param feed The feed + * @param iri The IRI of the next feed document + * @return The newly created Link + */ + public static Link setNext(Feed feed, String iri) { + Link link = feed.getLink("next"); + if (link != null) { + link.setHref(iri); + } else { + link = feed.addLink(iri, "next"); + } + return link; + } + + /** + * Adds a previous link relation to the feed + * @param feed The feed + * @param iri The IRI of the previous feed document + * @return The newly created Link + */ + public static Link setPrevious(Feed feed, String iri) { + Link link = feed.getLink("previous"); + if (link != null) { + link.setHref(iri); + } else { + link = feed.addLink(iri, "previous"); + } + return link; + } + + /** + * Adds a first link relation to the feed + * @param feed The feed + * @param iri The IRI of the first feed document + * @return The newly created Link + */ + public static Link setFirst(Feed feed, String iri) { + Link link = feed.getLink("first"); + if (link != null) { + link.setHref(iri); + } else { + link = feed.addLink(iri, "first"); + } + return link; + } + + /** + * Adds a last link relation to the feed + * @param feed The feed + * @param iri The IRI of the last feed document + * @return The newly created Link + */ + public static Link setLast(Feed feed, String iri) { + Link link = feed.getLink("last"); + if (link != null) { + link.setHref(iri); + } else { + link = feed.addLink(iri, "last"); + } + return link; + } + + /** + * Adds a next-archive link relation to the feed + * @param feed The feed + * @param iri The IRI of the next archive feed document + * @return The newly created Link + */ + public static Link setNextArchive(Feed feed, String iri) { + Link link = feed.getLink("next-archive"); + if (link == null) { // try the full IANA URI version + link = feed.getLink(Link.IANA_BASE + "next-archive"); + } + if (link != null) { + link.setHref(iri); + } else { + link = feed.addLink(iri, "next-archive"); + } + return link; + } + + /** + * Adds a prev-archive link relation to the feed + * @param feed The feed + * @param iri The IRI of the previous archive feed document + * @return The newly created Link + */ + public static Link setPreviousArchive(Feed feed, String iri) { + Link link = feed.getLink("prev-archive"); + if (link == null) { // try the full IANA URI version + link = feed.getLink(Link.IANA_BASE + "prev-archive"); + } + if (link != null) { + link.setHref(iri); + } else { + link = feed.addLink(iri, "prev-archive"); + } + return link; + } + + /** + * Adds a current link relation to the feed + * @param feed The feed + * @param iri The IRI of the current feed document + * @return The newly created Link + */ + public static Link setCurrent(Feed feed, String iri) { + Link link = feed.getLink("current"); + if (link == null) { // try the full IANA URI version + link = feed.getLink(Link.IANA_BASE + "current"); + } + if (link != null) { + link.setHref(iri); + } else { + link = feed.addLink(iri, "current"); + } + return link; + } + + /** + * Returns the IRI of the next link relation + */ + public static IRI getNext(Feed feed) { + Link link = feed.getLink("next"); + return (link != null) ? link.getResolvedHref() : null; + } + + /** + * Returns the IRI of the previous link relation + */ + public static IRI getPrevious(Feed feed) { + Link link = feed.getLink("previous"); + return (link != null) ? link.getResolvedHref() : null; + } + + /** + * Returns the IRI of the first link relation + */ + public static IRI getFirst(Feed feed) { + Link link = feed.getLink("first"); + return (link != null) ? link.getResolvedHref() : null; + } + + /** + * Returns the IRI of the last link relation + */ + public static IRI getLast(Feed feed) { + Link link = feed.getLink("last"); + return (link != null) ? link.getResolvedHref() : null; + } + + /** + * Returns the IRI of the prev-archive link relation + */ + public static IRI getPreviousArchive(Feed feed) { + Link link = feed.getLink("prev-archive"); + if (link == null) { // try the full IANA URI version + link = feed.getLink(Link.IANA_BASE + "prev-archive"); + } + return (link != null) ? link.getResolvedHref() : null; + } + + /** + * Returns the IRI of the next-archive link relation + */ + public static IRI getNextArchive(Feed feed) { + Link link = feed.getLink("next-archive"); + if (link == null) { // try the full IANA URI version + link = feed.getLink(Link.IANA_BASE + "next-archive"); + } + return (link != null) ? link.getResolvedHref() : null; + } + + /** + * Returns the IRI of the current link relation + */ + public static IRI getCurrent(Feed feed) { + Link link = feed.getLink("current"); + if (link == null) { // try the full IANA URI version + link = feed.getLink(Link.IANA_BASE + "current"); + } + return (link != null) ? link.getResolvedHref() : null; + } +} Added: incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/license/LicenseHelper.java URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/license/LicenseHelper.java?rev=567888&view=auto ============================================================================== --- incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/license/LicenseHelper.java (added) +++ incubator/abdera/java/trunk/extensions/main/src/main/java/org/apache/abdera/ext/license/LicenseHelper.java Mon Aug 20 17:51:20 2007 @@ -0,0 +1,150 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. 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. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.abdera.ext.license; + +import java.util.List; + +import org.apache.abdera.i18n.iri.IRI; +import org.apache.abdera.model.Base; +import org.apache.abdera.model.Entry; +import org.apache.abdera.model.Link; +import org.apache.abdera.model.Source; + +/** + * Implementation of the Atom License Extension, RFC 4946 + */ +public final class LicenseHelper { + + public static final String UNSPECIFIED_LICENSE = "http://purl.org/atompub/license#unspecified"; + + LicenseHelper() {} + + public static List getLicense( + Base base, + boolean inherited) { + List links = null; + if (base instanceof Source) { + links = ((Source)base).getLinks(Link.REL_LICENSE); + } else if (base instanceof Entry) { + Entry entry = (Entry)base; + Source source = entry.getSource(); + Base parent = entry.getParentElement(); + links = entry.getLinks(Link.REL_LICENSE); + if (inherited && (links == null || links.size() == 0) && source != null) { + links = getLicense(source, false); + } + if (inherited && (links == null || links.size() == 0) && parent != null) { + links = getLicense(parent, false); + } + } + return links; + } + + public static List getLicense( + Base base) { + return getLicense(base, true); + } + + public static boolean hasUnspecifiedLicense( + Base base, + boolean inherited) { + return hasLicense(base, UNSPECIFIED_LICENSE, inherited); + } + + public static boolean hasUnspecifiedLicense( + Base base) { + return hasUnspecifiedLicense(base, true); + } + + public static boolean hasLicense( + Base base, + String iri, + boolean inherited) { + List links = getLicense(base, inherited); + IRI check = new IRI(iri); + boolean answer = false; + if (links != null) { + for (Link link : links) { + if (link.getResolvedHref().equals(check)) { + answer = true; + break; + } + } + } + return answer; + } + + public static boolean hasLicense( + Base base, + String iri) { + return hasLicense(base, iri, true); + } + + public static boolean hasLicense( + Base base, + boolean inherited) { + List links = getLicense(base, inherited); + return (links != null && links.size() > 0); + } + + public static boolean hasLicense( + Base base) { + return hasLicense(base, true); + } + + public static Link addUnspecifiedLicense( + Base base) { + if (hasUnspecifiedLicense(base,false)) + throw new IllegalStateException("Unspecified license already added"); + if (hasLicense(base,false)) + throw new IllegalStateException("Other licenses are already added."); + return addLicense(base, UNSPECIFIED_LICENSE); + } + + public static Link addLicense( + Base base, + String iri) { + return addLicense(base, iri, null, null, null); + } + + public static Link addLicense( + Base base, + String iri, + String title) { + return addLicense(base, iri, null, title, null); + } + + public static Link addLicense( + Base base, + String iri, + String type, + String title, + String hreflang) { + if (hasLicense(base, iri,false)) + throw new IllegalStateException("License '" + iri + "' has already been added"); + if (hasUnspecifiedLicense(base,false)) + throw new IllegalStateException("Unspecified license already added"); + if (base instanceof Source) { + return ((Source)base).addLink((new IRI(iri)).toString(), Link.REL_LICENSE, type, title, hreflang, -1); + } else if (base instanceof Entry) { + return ((Entry)base).addLink((new IRI(iri)).toString(), Link.REL_LICENSE, type, title, hreflang, -1); + } + return null; + } + +}