Return-Path: X-Original-To: apmail-abdera-commits-archive@www.apache.org Delivered-To: apmail-abdera-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A58E27BB9 for ; Tue, 20 Sep 2011 15:59:41 +0000 (UTC) Received: (qmail 87695 invoked by uid 500); 20 Sep 2011 15:59:41 -0000 Delivered-To: apmail-abdera-commits-archive@abdera.apache.org Received: (qmail 87645 invoked by uid 500); 20 Sep 2011 15:59:41 -0000 Mailing-List: contact commits-help@abdera.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@abdera.apache.org Delivered-To: mailing list commits@abdera.apache.org Received: (qmail 87635 invoked by uid 99); 20 Sep 2011 15:59:41 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 20 Sep 2011 15:59:41 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 20 Sep 2011 15:59:36 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 049722388C90 for ; Tue, 20 Sep 2011 15:58:02 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1173209 [37/49] - in /abdera/abdera2: ./ .settings/ activities/ activities/src/ activities/src/main/ activities/src/main/java/ activities/src/main/java/org/ activities/src/main/java/org/apache/ activities/src/main/java/org/apache/abdera2/ ... Date: Tue, 20 Sep 2011 15:57:20 -0000 To: commits@abdera.apache.org From: jmsnell@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20110920155802.049722388C90@eris.apache.org> Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/serializer/impl/WorkspaceSerializer.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/serializer/impl/WorkspaceSerializer.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/serializer/impl/WorkspaceSerializer.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/serializer/impl/WorkspaceSerializer.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,41 @@ +/* + * 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.abdera2.ext.serializer.impl; + +import org.apache.abdera2.common.Constants; +import org.apache.abdera2.ext.serializer.Conventions; +import org.apache.abdera2.ext.serializer.ObjectContext; +import org.apache.abdera2.ext.serializer.SerializationContext; +import org.apache.abdera2.ext.serializer.annotation.Collection; + +public class WorkspaceSerializer extends ElementSerializer { + + public WorkspaceSerializer() { + super(Constants.WORKSPACE); + } + + protected void process(Object source, + ObjectContext objectContext, + SerializationContext context, + Conventions conventions) { + writeAttributes(source, objectContext, context, conventions); + writeExtensions(source, objectContext, context, conventions); + writeElements(Collection.class, new CollectionSerializer(), source, objectContext, context, conventions); + writeExtensions(source, objectContext, context, conventions); + } +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/serializer/impl/WorkspaceSerializer.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Conflicts.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Conflicts.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Conflicts.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Conflicts.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,48 @@ +/* + * 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.abdera2.ext.sharing; + +import java.util.List; + +import org.apache.abdera2.common.Constants; +import org.apache.abdera2.common.anno.QName; +import org.apache.abdera2.factory.Factory; +import org.apache.abdera2.model.Element; +import org.apache.abdera2.model.Entry; +import org.apache.abdera2.model.ExtensibleElementWrapper; + +@QName(value="conflicts",ns=SharingHelper.SSENS,pfx=SharingHelper.SSEPFX) +public class Conflicts extends ExtensibleElementWrapper { + + public Conflicts(Element internal) { + super(internal); + } + + public Conflicts(Factory factory, javax.xml.namespace.QName qname) { + super(factory, qname); + } + + public List getEntries() { + return getExtensions(Constants.ENTRY); + } + + public void addEntry(Entry entry) { + addExtension((Entry)entry.clone()); + } + +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Conflicts.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/History.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/History.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/History.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/History.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,79 @@ +/* + * 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.abdera2.ext.sharing; + +import java.util.Date; + +import org.apache.abdera2.factory.Factory; +import org.apache.abdera2.common.anno.QName; +import org.apache.abdera2.common.date.DateTime; +import org.apache.abdera2.model.Element; +import org.apache.abdera2.model.ElementWrapper; + +@QName(value="history",ns=SharingHelper.SSENS,pfx=SharingHelper.SSEPFX) +public class History extends ElementWrapper { + + public History(Element internal) { + super(internal); + } + + public History(Factory factory, javax.xml.namespace.QName qname) { + super(factory, qname); + } + + public int getSequence() { + String sequence = getAttributeValue("sequence"); + return sequence != null ? Integer.parseInt(sequence) : 0; + } + + public void setSequence(int sequence) { + if (sequence > 0) { + setAttributeValue("sequence", Integer.toString(sequence)); + } else { + removeAttribute("sequence"); + } + } + + public Date getWhen() { + String when = getAttributeValue("when"); + return when != null ? DateTime.parse(when) : null; + } + + public void setWhen(Date when) { + if (when != null) { + setAttributeValue("when", DateTime.format(when)); + } else { + removeAttribute("when"); + } + } + + public String getBy() { + return getAttributeValue("by"); + } + + public void setBy(String by) { + if (by != null) { + if (!SharingHelper.isValidEndpointIdentifier(by)) + throw new IllegalArgumentException("Invalid Endpoint Identifier"); + setAttributeValue("by", by); + } else { + removeAttribute("by"); + } + } + +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/History.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Related.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Related.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Related.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Related.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,79 @@ +/* + * 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.abdera2.ext.sharing; + +import org.apache.abdera2.factory.Factory; +import org.apache.abdera2.common.anno.QName; +import org.apache.abdera2.common.iri.IRI; +import org.apache.abdera2.model.Element; +import org.apache.abdera2.model.ElementWrapper; + +@QName(value="related",ns=SharingHelper.SSENS,pfx=SharingHelper.SSEPFX) +public class Related extends ElementWrapper { + + public static enum Type { + COMPLETE, AGGREGATED + }; + + public Related(Element internal) { + super(internal); + } + + public Related(Factory factory, javax.xml.namespace.QName qname) { + super(factory, qname); + } + + public IRI getLink() { + String link = getAttributeValue("link"); + return link != null ? new IRI(link) : null; + } + + public void setLink(String link) { + if (link != null) { + setAttributeValue("link", new IRI(link).toString()); + } else { + removeAttribute("link"); + } + } + + public String getTitle() { + return getAttributeValue("title"); + } + + public void setTitle(String title) { + if (title != null) { + setAttributeValue("title", title); + } else { + removeAttribute("title"); + } + } + + public Type getType() { + String type = getAttributeValue("type"); + return type != null ? Type.valueOf(type.toUpperCase()) : null; + } + + public void setType(Type type) { + if (type != null) { + setAttributeValue("type", type.name().toLowerCase()); + } else { + removeAttribute("type"); + } + } + +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Related.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Sharing.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Sharing.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Sharing.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Sharing.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,98 @@ +/* + * 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.abdera2.ext.sharing; + +import java.util.Date; +import java.util.List; + +import org.apache.abdera2.factory.Factory; +import org.apache.abdera2.common.anno.QName; +import org.apache.abdera2.common.date.DateTime; +import org.apache.abdera2.model.Element; +import org.apache.abdera2.model.ExtensibleElementWrapper; + +@QName(value="sharing",ns=SharingHelper.SSENS,pfx=SharingHelper.SSEPFX) +public class Sharing extends ExtensibleElementWrapper { + + public Sharing(Element internal) { + super(internal); + } + + public Sharing(Factory factory, javax.xml.namespace.QName qname) { + super(factory, qname); + } + + public Date getSince() { + String since = getAttributeValue("since"); + return since != null ? DateTime.parse(since) : null; + } + + public void setSince(Date since) { + if (since != null) { + setAttributeValue("since", DateTime.format(since)); + } else { + removeAttribute("since"); + } + } + + public Date getUntil() { + String until = getAttributeValue("until"); + return until != null ? DateTime.parse(until) : null; + } + + public void setUntil(Date until) { + if (until != null) { + setAttributeValue("until", DateTime.format(until)); + } else { + removeAttribute("until"); + } + } + + public Date getExpires() { + String expires = getAttributeValue("expires"); + return expires != null ? DateTime.parse(expires) : null; + } + + public void setExpires(Date expires) { + if (expires != null) { + setAttributeValue("expires", DateTime.format(expires)); + } else { + removeAttribute("expires"); + } + } + + public List getRelated() { + return getExtensions(SharingHelper.SSE_RELATED); + } + + public void addRelated(Related related) { + addExtension(related); + } + + public Related addRelated() { + return getFactory().newElement(SharingHelper.SSE_RELATED, this); + } + + public Related addRelated(String link, String title, Related.Type type) { + Related related = addRelated(); + related.setLink(link); + related.setTitle(title); + related.setType(type); + return related; + } +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Sharing.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/SharingExtensionFactory.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/SharingExtensionFactory.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/SharingExtensionFactory.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/SharingExtensionFactory.java Tue Sep 20 15:56:46 2011 @@ -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.abdera2.ext.sharing; + +import org.apache.abdera2.common.anno.Namespace; +import org.apache.abdera2.factory.AbstractExtensionFactory; +import org.apache.abdera2.factory.AbstractExtensionFactory.Impls; +import org.apache.abdera2.factory.AbstractExtensionFactory.Impl; +import static org.apache.abdera2.ext.sharing.SharingHelper.*; +@Namespace(SSENS) +@Impls( + { + @Impl(Conflicts.class), + @Impl(History.class), + @Impl(Related.class), + @Impl(Sharing.class), + @Impl(Sync.class), + @Impl(Unpublished.class) + } +) +public class SharingExtensionFactory extends AbstractExtensionFactory {} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/SharingExtensionFactory.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/SharingHelper.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/SharingHelper.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/SharingHelper.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/SharingHelper.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,467 @@ +/* + * 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.abdera2.ext.sharing; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +import org.apache.abdera2.Abdera; +import org.apache.abdera2.model.Base; +import org.apache.abdera2.model.Entry; +import org.apache.abdera2.model.Feed; +import org.apache.abdera2.model.Source; + +public class SharingHelper { + + public static final String SSENS = "http://feedsync.org/2007/feedsync"; + public static final String SSEPFX = "sx"; + + public static final QName SSE_SHARING = new QName(SSENS, "sharing", SSEPFX); + public static final QName SSE_RELATED = new QName(SSENS, "related", SSEPFX); + public static final QName SSE_CONFLICTS = new QName(SSENS, "conflicts", SSEPFX); + public static final QName SSE_HISTORY = new QName(SSENS, "history", SSEPFX); + public static final QName SSE_SYNC = new QName(SSENS, "sync", SSEPFX); + public static final QName SSE_UNPUBLISHED = new QName(SSENS, "unpublished", SSEPFX); + + protected static boolean isTrue(String value) { + return value.equalsIgnoreCase("true") || value.equals("1") || value.equals("-1") || value.equals("yes"); + } + + public static Sharing getSharing(T source) { + return getSharing(source, false); + } + + public static Sharing getSharing(T source, boolean create) { + Sharing sharing = source.getExtension(SSE_SHARING); + if (sharing == null && create) + sharing = source.addExtension(SSE_SHARING); + return sharing; + } + + public static boolean hasSharing(T source) { + return getSharing(source) != null; + } + + public static Unpublished getUnpublished(Feed feed) { + return getUnpublished(feed, false); + } + + public static Unpublished getUnpublished(Feed feed, boolean create) { + Unpublished unpub = feed.getExtension(SSE_UNPUBLISHED); + if (unpub == null && create) + unpub = feed.addExtension(SSE_UNPUBLISHED); + return unpub; + } + + public static Sync getSync(Entry entry) { + return getSync(entry, false); + } + + public static Sync getSync(Entry entry, boolean create) { + Sync sync = entry.getExtension(SSE_SYNC); + if (sync == null && create) + sync = entry.addExtension(SSE_SYNC); + return sync; + } + + public static boolean hasSync(Entry entry) { + return getSync(entry, false) != null; + } + + public static Entry createEntry(Abdera abdera, String by) { + return createEntry(abdera, by, null); + } + + public static Entry createEntry(Abdera abdera, String by, Feed feed) { + Entry entry = feed != null ? feed.addEntry() : abdera.newEntry(); + entry.newId(); + Sync sync = getSync(entry, true); + sync.setId(entry.getId().toString()); + sync.setUpdates(1); + History history = sync.addHistory(); + history.setSequence(sync.getUpdates()); + history.setWhen(new Date()); + history.setBy(by); + return entry; + } + + public static void deleteEntry(Entry entry, String by) { + Sync sync = getSync(entry, true); + sync.incrementUpdates(); + sync.setDeleted(true); + History history = sync.addHistory(); + history.setSequence(sync.getUpdates()); + history.setWhen(new Date()); + history.setBy(by); + } + + public static void updateEntry(Entry entry, String by) { + Sync sync = getSync(entry, true); + sync.incrementUpdates(); + History history = sync.addHistory(); + history.setSequence(sync.getUpdates()); + history.setWhen(new Date()); + history.setBy(by); + } + + public static Map getSyncIdMap(Feed feed) { + Map entries = new HashMap(); + for (Entry entry : feed.getEntries()) { + Sync sync = getSync(entry, false); + if (sync != null) { + String id = sync.getId(); + if (id != null) { + entries.put(id, entry); + } + } + } + return entries; + } + + public static boolean isSubsumed(Sync s1, Sync s2) { + if (s1 == null && s2 == null) + return false; + if (s1 == null && s2 != null) + return true; + if (s1 != null && s2 == null) + return false; + if (s1.equals(s2)) + return false; + if (!s1.getId().equals(s2.getId())) + return false; + History h1 = s1.getFirstChild(SSE_HISTORY); + for (History h2 : s2.getHistory()) { + if (isSubsumed(h1, h2)) + return true; + } + return false; + } + + public static boolean isSubsumed(History h1, History h2) { + if (h1 == null && h2 == null) + return false; + if (h1 == null && h2 != null) + return true; + if (h1 != null && h2 == null) + return false; + if (h1.equals(h2)) + return false; + String h1by = h1.getBy(); + String h2by = h2.getBy(); + if (h1by != null) { + if (h2by != null && h1by.equals(h2by) && h2.getSequence() >= h1.getSequence()) + return true; + } else { + if (h2by == null && h1.getWhen().equals(h2.getWhen()) && h1.getSequence() == h2.getSequence()) + return true; + } + return false; + } + + public static Sync pickWinner(Sync s1, Sync s2) { + if (s1 == null && s2 == null) + return null; + if (s1 == null && s2 != null) + return s2; + if (s1 != null && s2 == null) + return s1; + if (s1.equals(s2)) + return s1; + if (!s1.getId().equals(s2.getId())) + return null; + if (s1.getUpdates() > s2.getUpdates()) + return s1; + if (s1.getUpdates() == s2.getUpdates()) { + History h1 = s1.getTopmostHistory(); + History h2 = s2.getTopmostHistory(); + Date d1 = h1.getWhen(); + Date d2 = h2.getWhen(); + if (d1 != null && d2 == null) + return s1; + if (d1.after(d2)) + return s1; + if (d1.equals(d2)) { + String b1 = h1.getBy(); + String b2 = h2.getBy(); + if (b1 != null && b2 == null) + return s1; + if (b1.compareTo(b2) > 0) + return s1; + } + } + return s2; + } + + private static List getConflicts(Entry entry) { + List list = new ArrayList(); + Sync sync = getSync(entry, false); + if (sync != null) { + Conflicts conflicts = sync.getConflicts(false); + if (conflicts != null) { + list.addAll(conflicts.getEntries()); + } + } + list.add(entry); + return list; + } + + private static Entry compareConflicts(Entry w, List outerList, List innerList, List results) { + Entry[] outer = outerList.toArray(new Entry[outerList.size()]); + Entry[] inner = innerList.toArray(new Entry[innerList.size()]); + for (Entry x : outer) { + Sync s1 = getSync(x, false); + boolean ok = true; + for (Entry y : inner) { + Sync s2 = getSync(y, false); + if (isSubsumed(s1, s2)) { + outerList.remove(s1); + ok = false; + break; + } + } + if (ok) { + results.add(x); + if (w == null) + w = x; + else { + Sync s2 = getSync(w); + if (pickWinner(s1, s2) == s1) + w = x; + } + } + } + return w; + } + + public static void mergeFeeds(Feed source, Feed dest) { + Map destentries = getSyncIdMap(dest); + for (Entry entry : source.getEntries()) { + Sync s2 = getSync(entry, false); + if (s2 != null) { + String id = s2.getId(); + if (id != null) { + Entry existing = destentries.get(id); + if (existing == null) { + Entry e = (Entry)entry.clone(); + dest.addEntry(e); + } else { + Sync s1 = getSync(existing, false); + List c1 = getConflicts(existing); + List c2 = getConflicts(entry); + List m = new ArrayList(); + Entry w = null; + w = compareConflicts(w, c1, c2, m); + w = compareConflicts(w, c2, c1, m); + // if (w != null) dest.addEntry((Entry)w.clone()); + if (s1.isNoConflicts()) + return; + if (m.size() > 0) { + Sync sync = getSync(w, true); + sync.setConflicts(null); + Conflicts conflicts = sync.getConflicts(true); + for (Entry e : m) { + if (e != w) + conflicts.addEntry(e); + } + } + } + } + } // otherwise skip the entry + } + } + + private static void mergeConflictItems(Entry entry, List conflicts) { + Sync sync = getSync(entry, true); + for (Entry x : conflicts) { + Sync xsync = getSync(x, false); + if (xsync != null) { + List list = xsync.getHistory(); + History[] history = list.toArray(new History[list.size()]); + for (History h1 : history) { + h1 = (History)h1.clone(); + h1.discard(); + boolean ok = true; + for (History h2 : sync.getHistory()) { + if (isSubsumed(h1, h2)) { + ok = false; + break; + } + } + if (ok) + sync.addHistory((History)h1); + } + } + } + } + + public static Entry resolveConflicts(Entry entry, ConflictResolver resolver, String by) { + List conflicts = getConflicts(entry); + entry = resolver.resolve(entry, conflicts); + updateEntry(entry, by); + mergeConflictItems(entry, conflicts); + return entry; + } + + public static interface ConflictResolver { + Entry resolve(Entry entry, List conflicts); + } + + public static Entry unpublish(Entry entry) { + if (entry == null) + return null; + Base base = entry.getParentElement(); + if (base == null || !(base instanceof Feed)) + return null; + Feed feed = (Feed)base; + Unpublished unpub = getUnpublished(feed, true); + Entry newentry = (Entry)entry.clone(); + newentry.setParentElement(unpub); + unpub.addEntry(newentry); + entry.discard(); + return newentry; + } + + public static Entry republish(Entry entry) { + if (entry == null) + return null; + Base base = entry.getParentElement(); + if (base == null || !(base instanceof Unpublished)) + return null; + Unpublished unpub = (Unpublished)base; + Feed feed = unpub.getParentElement(); + Entry newentry = (Entry)entry.clone(); + newentry.setParentElement(feed); + feed.addEntry(newentry); + entry.discard(); + return newentry; + } + + public static void publish(Feed feed, Date expires, boolean initial) { + if (initial) { + Sharing sharing = getSharing(feed, true); + Date since = getMin(feed); + Date until = getMax(feed); + sharing.setSince(since); + sharing.setUntil(until); + sharing.setExpires(expires); + } else { + Sharing sharing = getSharing(feed, false); + if (sharing != null) { + sharing.setExpires(expires); + } else { + publish(feed, expires, true); + } + } + } + + private static Date getMax(Feed feed) { + Date d = null; + for (Entry entry : feed.getEntries()) { + Date updated = entry.getUpdated(); + if (d == null) + d = updated; + if (updated.after(d)) + d = updated; + } + return d; + } + + private static Date getMin(Feed feed) { + Date d = null; + for (Entry entry : feed.getEntries()) { + Date updated = entry.getUpdated(); + if (d == null) + d = updated; + if (updated.before(d)) + d = updated; + } + return d; + } + + public static boolean hasConflicts(Entry entry) { + Sync sync = getSync(entry); + if (sync != null) { + Conflicts conflicts = sync.getConflicts(); + if (conflicts != null) { + if (conflicts.getEntries().size() > 0) { + return true; + } + } + } + return false; + } + + public static boolean isValidEndpointIdentifier(String id) { + if (id == null) + return false; + char[] chars = id.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + if (!is_alphanum(c) && !is_reserved_or_other(c) && !is_hex(chars, i)) { + return false; + } + } + return true; + } + + private static boolean is_alphanum(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); + } + + private static boolean is_reserved_or_other(char c) { + return c == '/' || c == '?' + || c == '#' + || c == '(' + || c == ')' + || c == '+' + || c == ',' + || c == '-' + || c == '.' + || c == ':' + || c == '=' + || c == '@' + || c == ';' + || c == '$' + || c == '_' + || c == '!' + || c == '*' + || c == '\''; + } + + private static boolean is_hex(char[] chars, int i) { + if (chars[i] == '%') { + if (i + 2 > chars.length) + return false; + return is_hex(chars[i], chars[i + 1], chars[i + 2]); + } + return false; + } + + private static boolean is_hexdigit(char c) { + return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9'); + } + + private static boolean is_hex(char c, char c2, char c3) { + return (c == '%' && is_hexdigit(c2) && is_hexdigit(c3)); + } +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/SharingHelper.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Sync.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Sync.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Sync.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Sync.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,136 @@ +/* + * 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.abdera2.ext.sharing; + +import java.util.Date; +import java.util.List; + +import org.apache.abdera2.common.anno.QName; +import org.apache.abdera2.factory.Factory; +import org.apache.abdera2.model.Element; +import org.apache.abdera2.model.ExtensibleElementWrapper; +@QName(value="sync",ns=SharingHelper.SSENS,pfx=SharingHelper.SSEPFX) +public class Sync extends ExtensibleElementWrapper { + + public Sync(Element internal) { + super(internal); + } + + public Sync(Factory factory, javax.xml.namespace.QName qname) { + super(factory, qname); + } + + public String getId() { + return getAttributeValue("id"); + } + + public void setId(String id) { + if (id != null) { + setAttributeValue("id", id); + } else { + removeAttribute("id"); + } + } + + public int getUpdates() { + String updates = getAttributeValue("updates"); + return updates != null ? Integer.parseInt(updates) : 0; + } + + public void setUpdates(int updates) { + if (updates > 0) { + setAttributeValue("updates", Integer.toString(updates)); + } else { + removeAttribute("updates"); + } + } + + public void incrementUpdates() { + setUpdates(getUpdates() + 1); + } + + public boolean isDeleted() { + String deleted = getAttributeValue("deleted"); + return deleted != null ? SharingHelper.isTrue(deleted) : false; + } + + public void setDeleted(boolean deleted) { + if (deleted) { + setAttributeValue("deleted", "true"); + } else { + removeAttribute("deleted"); + } + } + + public boolean isNoConflicts() { + String noconflicts = getAttributeValue("noconflicts"); + return noconflicts != null ? SharingHelper.isTrue(noconflicts) : false; + } + + public void setNoConflicts(boolean noconflicts) { + if (noconflicts) { + setAttributeValue("noconflicts", "true"); + } else { + removeAttribute("noconflicts"); + } + } + + public List getHistory() { + return getExtensions(SharingHelper.SSE_HISTORY); + } + + public void addHistory(History history) { + this.addExtension(history); + } + + public History addHistory() { + return this.addExtension(SharingHelper.SSE_HISTORY, SharingHelper.SSE_HISTORY); + } + + public History addHistory(int sequence, Date when, String by) { + History history = addHistory(); + history.setSequence(sequence); + history.setWhen(when); + history.setBy(by); + return history; + } + + public History getTopmostHistory() { + return this.getFirstChild(SharingHelper.SSE_HISTORY); + } + + public Conflicts getConflicts() { + return getConflicts(false); + } + + public void setConflicts(Conflicts conflicts) { + Conflicts con = getConflicts(); + if (con != null) + con.discard(); + if (conflicts != null) + addExtension(conflicts); + } + + public Conflicts getConflicts(boolean create) { + Conflicts con = getExtension(SharingHelper.SSE_CONFLICTS); + if (con == null && create) + con = getFactory().newElement(SharingHelper.SSE_CONFLICTS, this.getInternal()); + return con; + } + +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Sync.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Unpublished.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Unpublished.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Unpublished.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Unpublished.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,48 @@ +/* + * 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.abdera2.ext.sharing; + +import java.util.List; + + +import org.apache.abdera2.common.Constants; +import org.apache.abdera2.common.anno.QName; +import org.apache.abdera2.factory.Factory; +import org.apache.abdera2.model.Element; +import org.apache.abdera2.model.Entry; +import org.apache.abdera2.model.ExtensibleElementWrapper; + +@QName(value="unpublished",ns=SharingHelper.SSENS,pfx=SharingHelper.SSEPFX) +public class Unpublished extends ExtensibleElementWrapper { + + public Unpublished(Element internal) { + super(internal); + } + + public Unpublished(Factory factory, javax.xml.namespace.QName qname) { + super(factory, qname); + } + + public List getEntries() { + return getExtensions(Constants.ENTRY); + } + + public void addEntry(Entry entry) { + addExtension((Entry)entry.clone()); + } +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/sharing/Unpublished.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/InReplyTo.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/InReplyTo.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/InReplyTo.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/InReplyTo.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,108 @@ +/* + * 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.abdera2.ext.thread; + +import javax.activation.MimeType; + +import org.apache.abdera2.factory.Factory; +import org.apache.abdera2.model.Element; +import org.apache.abdera2.model.ElementWrapper; +import org.apache.abdera2.common.anno.QName; +import org.apache.abdera2.common.iri.IRI; +import static org.apache.abdera2.ext.thread.ThreadConstants.*; + +@QName(value=LN_INREPLYTO,ns=THR_NS,pfx=THR_PREFIX) +public class InReplyTo extends ElementWrapper { + + public InReplyTo(Element internal) { + super(internal); + } + + public InReplyTo(Factory factory) { + super(factory, ThreadConstants.IN_REPLY_TO); + } + + public IRI getHref() { + String href = getAttributeValue("href"); + return (href != null) ? new IRI(href) : null; + } + + public MimeType getMimeType() { + try { + String type = getAttributeValue("type"); + return (type != null) ? new MimeType(type) : null; + } catch (javax.activation.MimeTypeParseException e) { + throw new org.apache.abdera2.common.mediatype.MimeTypeParseException(e); + } + } + + public IRI getRef() { + String ref = getAttributeValue("ref"); + return (ref != null) ? new IRI(ref) : null; + } + + public IRI getResolvedHref() { + IRI href = getHref(); + IRI base = getBaseUri(); + return (base == null) ? href : (href != null) ? base.resolve(href) : null; + } + + public IRI getResolvedSource() { + IRI href = getSource(); + IRI base = getBaseUri(); + return (base == null) ? href : (href != null) ? base.resolve(href) : null; + } + + public IRI getSource() { + String source = getAttributeValue("source"); + return (source != null) ? new IRI(source) : null; + } + + public void setHref(IRI ref) { + setAttributeValue("href", ref.toString()); + } + + public void setHref(String ref) { + setAttributeValue("href", ref); + } + + public void setMimeType(MimeType mimeType) { + setAttributeValue("type", mimeType.toString()); + } + + public void setMimeType(String mimeType) { + setAttributeValue("type", mimeType); + } + + public void setRef(IRI ref) { + setAttributeValue("ref", ref.toString()); + } + + public void setRef(String ref) { + setAttributeValue("ref", ref); + } + + public void setSource(IRI source) { + setAttributeValue("source", source.toString()); + } + + public void setSource(String source) { + setAttributeValue("source", source); + } + +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/InReplyTo.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadConstants.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadConstants.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadConstants.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadConstants.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,42 @@ +/* + * 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.abdera2.ext.thread; + +import javax.xml.namespace.QName; + +import org.apache.abdera2.common.Constants; + +public interface ThreadConstants extends Constants { + + public static final String THR_NS = "http://purl.org/syndication/thread/1.0"; + public static final String LN_INREPLYTO = "in-reply-to"; + public static final String LN_REF = "ref"; + public static final String LN_COUNT = "count"; + public static final String LN_WHEN = "when"; + public static final String LN_TOTAL = "total"; + public static final String THR_PREFIX = "thr"; + public static final QName IN_REPLY_TO = new QName(THR_NS, LN_INREPLYTO, THR_PREFIX); + public static final QName THRCOUNT = new QName(THR_NS, LN_COUNT, THR_PREFIX); + /** @deprecated Use Constants.THRUPDATED */ + public static final QName THRWHEN = new QName(THR_NS, LN_WHEN, THR_PREFIX); + public static final QName THRUPDATED = new QName(THR_NS, LN_UPDATED, THR_PREFIX); + public static final QName THRTOTAL = new QName(THR_NS, LN_TOTAL, THR_PREFIX); + public static final QName THRREF = new QName(LN_REF); + public static final QName THRSOURCE = new QName(LN_SOURCE); + +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadConstants.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadExtensionFactory.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadExtensionFactory.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadExtensionFactory.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadExtensionFactory.java Tue Sep 20 15:56:46 2011 @@ -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.abdera2.ext.thread; + +import org.apache.abdera2.common.anno.Namespace; +import org.apache.abdera2.factory.AbstractExtensionFactory; +import org.apache.abdera2.factory.AbstractExtensionFactory.Impls; +import org.apache.abdera2.factory.AbstractExtensionFactory.Impl; + +@Namespace(ThreadConstants.THR_NS) +@Impls({ + @Impl(InReplyTo.class), + @Impl(Total.class) +}) +public final class ThreadExtensionFactory extends AbstractExtensionFactory implements ThreadConstants {} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadExtensionFactory.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadHelper.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadHelper.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadHelper.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadHelper.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,169 @@ +/* + * 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.abdera2.ext.thread; + +import java.util.Calendar; +import java.util.Date; + +import javax.activation.MimeType; + +import org.apache.abdera2.factory.Factory; +import org.apache.abdera2.common.date.DateTime; +import org.apache.abdera2.model.Entry; +import org.apache.abdera2.model.Link; +import org.apache.abdera2.model.Source; +import org.apache.abdera2.common.iri.IRI; + +public final class ThreadHelper { + + ThreadHelper() { + } + + public static int getCount(Link link) { + String val = link.getAttributeValue(ThreadConstants.THRCOUNT); + return (val != null) ? Integer.parseInt(val) : 0; + } + + @SuppressWarnings("deprecation") + public static DateTime getUpdated(Link link) { + String val = link.getAttributeValue(ThreadConstants.THRUPDATED); + if (val == null) // thr:when was updated to thr:updated, some old impls may still be using thr:when + val = link.getAttributeValue(ThreadConstants.THRWHEN); + return (val != null) ? DateTime.valueOf(val) : null; + } + + public static void setCount(Link link, int count) { + link.setAttributeValue(ThreadConstants.THRCOUNT, String.valueOf(count).trim()); + } + + public static void setUpdated(Link link, Date when) { + link.setAttributeValue(ThreadConstants.THRUPDATED, DateTime.valueOf(when).getValue()); + } + + public static void setUpdated(Link link, Calendar when) { + link.setAttributeValue(ThreadConstants.THRUPDATED, DateTime.valueOf(when).getValue()); + } + + public static void setUpdated(Link link, long when) { + link.setAttributeValue(ThreadConstants.THRUPDATED, DateTime.valueOf(when).getValue()); + } + + public static void setUpdated(Link link, String when) { + link.setAttributeValue(ThreadConstants.THRUPDATED, DateTime.valueOf(when).getValue()); + } + + public static Total addTotal(Entry entry, int total) { + Factory factory = entry.getFactory(); + Total totalelement = (Total)factory.newExtensionElement(ThreadConstants.THRTOTAL, entry); + totalelement.setValue(total); + return totalelement; + } + + public static Total getTotal(Entry entry) { + return entry.getFirstChild(ThreadConstants.THRTOTAL); + } + + public static void addInReplyTo(Entry entry, InReplyTo replyTo) { + entry.addExtension(replyTo); + } + + public static InReplyTo addInReplyTo(Entry entry) { + return entry.addExtension(ThreadConstants.IN_REPLY_TO); + } + + public static InReplyTo addInReplyTo(Entry entry, Entry ref) { + if (ref.equals(entry)) + return null; + InReplyTo irt = addInReplyTo(entry); + try { + irt.setRef(ref.getId()); + Link altlink = ref.getAlternateLink(); + if (altlink != null) { + irt.setHref(altlink.getResolvedHref()); + if (altlink.getMimeType() != null) + irt.setMimeType(altlink.getMimeType()); + } + Source src = ref.getSource(); + if (src != null) { + Link selflink = src.getSelfLink(); + if (selflink != null) + irt.setSource(selflink.getResolvedHref()); + } + } catch (Exception e) { + } + return irt; + } + + public static InReplyTo addInReplyTo(Entry entry, IRI ref) { + try { + if (entry.getId() != null && entry.getId().equals(ref)) + return null; + } catch (Exception e) { + } + InReplyTo irt = addInReplyTo(entry); + irt.setRef(ref); + return irt; + } + + public static InReplyTo addInReplyTo(Entry entry, String ref) { + return addInReplyTo(entry, new IRI(ref)); + } + + public static InReplyTo addInReplyTo(Entry entry, IRI ref, IRI source, IRI href, MimeType type) { + InReplyTo irt = addInReplyTo(entry, ref); + if (irt != null) { + if (source != null) + irt.setSource(source); + if (href != null) + irt.setHref(href); + if (type != null) + irt.setMimeType(type); + } + return irt; + } + + public static InReplyTo addInReplyTo(Entry entry, String ref, String source, String href, String type) { + InReplyTo irt = addInReplyTo(entry, ref); + if (irt != null) { + if (source != null) + irt.setSource(source); + if (href != null) + irt.setHref(href); + if (type != null) + irt.setMimeType(type); + } + return irt; + } + + public static InReplyTo getInReplyTo(Entry entry) { + return entry.getFirstChild(ThreadConstants.IN_REPLY_TO); + } + + public static Iterable getInReplyTos(Entry entry) { + return entry.getExtensions(ThreadConstants.IN_REPLY_TO); + } + + public static InReplyTo newInReplyTo(Factory factory) { + return new InReplyTo(factory); + } + + public static Total newTotal(Factory factory) { + return new Total(factory); + } + +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/ThreadHelper.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/Total.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/Total.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/Total.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/Total.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,46 @@ +/* + * 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.abdera2.ext.thread; + +import org.apache.abdera2.common.anno.QName; +import org.apache.abdera2.factory.Factory; +import org.apache.abdera2.model.Element; +import org.apache.abdera2.model.ElementWrapper; +import static org.apache.abdera2.ext.thread.ThreadConstants.*; + +@QName(value=LN_TOTAL,ns=THR_NS,pfx=THR_PREFIX) +public class Total extends ElementWrapper { + + public Total(Element internal) { + super(internal); + } + + public Total(Factory factory) { + super(factory, ThreadConstants.THRTOTAL); + } + + public int getValue() { + String val = getText(); + return (val != null) ? Integer.parseInt(val) : -1; + } + + public void setValue(int value) { + setText(String.valueOf(value)); + } + +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/thread/Total.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/Tombstone.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/Tombstone.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/Tombstone.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/Tombstone.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,138 @@ +/* + * 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.abdera2.ext.tombstones; + +import java.util.Calendar; +import java.util.Date; + +import org.apache.abdera2.factory.Factory; +import org.apache.abdera2.common.iri.IRI; +import org.apache.abdera2.common.anno.QName; +import org.apache.abdera2.common.date.DateTime; +import org.apache.abdera2.model.Element; +import org.apache.abdera2.model.ExtensibleElementWrapper; +import org.apache.abdera2.model.Person; +import org.apache.abdera2.model.Text; + +@QName(value="deleted-entry",ns=TombstonesHelper.TNS) +public class Tombstone extends ExtensibleElementWrapper { + + public Tombstone(Element internal) { + super(internal); + } + + public Tombstone(Factory factory) { + super(factory, TombstonesHelper.DELETED_ENTRY); + } + + public String getRef() { + return getAttributeValue("ref"); + } + + public Tombstone setRef(String id) { + if (id != null) { + setAttributeValue("ref", id); + } else { + removeAttribute("ref"); + } + return this; + } + + public Tombstone setRef(IRI id) { + return setRef(id.toString()); + } + + public Date getWhen() { + String v = getAttributeValue("when"); + return v != null ? DateTime.parse(v) : null; + } + + public Tombstone setWhen(Date date) { + return setWhen(DateTime.format(date)); + } + + public Tombstone setWhen(String date) { + if (date != null) { + setAttributeValue("when", date); + } else { + removeAttribute("when"); + } + return this; + } + + public Tombstone setWhen(long date) { + return setWhen(DateTime.valueOf(date)); + } + + public Tombstone setWhen(Calendar date) { + return setWhen(DateTime.valueOf(date)); + } + + public Tombstone setWhen(DateTime date) { + return setWhen(date.toString()); + } + + public Person getBy() { + return getExtension(TombstonesHelper.BY); + } + + public Tombstone setBy(Person person) { + if (getBy() != null) + getBy().discard(); + addExtension(person); + return this; + } + + public Person setBy(String name) { + return setBy(name, null, null); + } + + public Person setBy(String name, String email, String uri) { + if (name != null) { + Person person = getFactory().newPerson(TombstonesHelper.BY, this); + person.setName(name); + person.setEmail(email); + person.setUri(uri); + return person; + } else { + if (getBy() != null) + getBy().discard(); + return null; + } + } + + public Text getComment() { + return getExtension(TombstonesHelper.COMMENT); + } + + public Text setComment(String comment) { + return setComment(Text.Type.TEXT, comment); + } + + public Text setComment(Text.Type type, String comment) { + if (comment != null) { + Text text = getFactory().newText(TombstonesHelper.COMMENT, type, this); + text.setValue(comment); + return text; + } else { + if (getComment() != null) + getComment().discard(); + return null; + } + } +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/Tombstone.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/TombstonesExtensionFactory.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/TombstonesExtensionFactory.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/TombstonesExtensionFactory.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/TombstonesExtensionFactory.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,27 @@ +/* + * 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.abdera2.ext.tombstones; + +import org.apache.abdera2.common.anno.Namespace; +import org.apache.abdera2.factory.AbstractExtensionFactory; +import org.apache.abdera2.factory.AbstractExtensionFactory.Impls; +import org.apache.abdera2.factory.AbstractExtensionFactory.Impl; + +@Namespace(TombstonesHelper.TNS) +@Impls({@Impl(Tombstone.class)}) +public final class TombstonesExtensionFactory extends AbstractExtensionFactory {} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/TombstonesExtensionFactory.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/TombstonesHelper.java URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/TombstonesHelper.java?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/TombstonesHelper.java (added) +++ abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/TombstonesHelper.java Tue Sep 20 15:56:46 2011 @@ -0,0 +1,147 @@ +/* + * 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.abdera2.ext.tombstones; + +import java.util.Calendar; +import java.util.Date; + +import javax.xml.namespace.QName; + +import org.apache.abdera2.common.date.DateTime; +import org.apache.abdera2.model.Base; +import org.apache.abdera2.model.Entry; +import org.apache.abdera2.model.Feed; + +/** + * Note this is an experimental implementation of the Tombstones specification. The tombstone spec is a work-in-progress + * and will continue to evolve. This extension should only be used for experimentation or prototype development. + * http://www.ietf.org/internet-drafts/draft-snell-atompub-tombstones-04.txt + */ +public class TombstonesHelper { + + public static final String TNS = "http://purl.org/atompub/tombstones/1.0"; + + public static final QName DELETED_ENTRY = new QName(TNS, "deleted-entry"); + public static final QName BY = new QName(TNS, "by"); + public static final QName COMMENT = new QName(TNS, "comment"); + + public static Iterable getTombstones(Feed source) { + return source.getExtensions(DELETED_ENTRY); + } + + public static void addTombstone(Feed source, Tombstone tombstone) { + source.addExtension(tombstone); + } + + public static Tombstone addTombstone(Feed source, Entry entry) { + Tombstone tombstone = source.getFactory().newExtensionElement(DELETED_ENTRY, source); + tombstone.setRef(entry.getId()); + Base parent = entry.getParentElement(); + if (parent != null && parent.equals(source)) + entry.discard(); + return tombstone; + } + + public static Tombstone addTombstone(Feed source, Entry entry, Date when, String by, String comment) { + Tombstone ts = addTombstone(source, entry); + ts.setWhen(when); + ts.setBy(by); + ts.setComment(comment); + return ts; + } + + public static Tombstone addTombstone(Feed source, Entry entry, String when, String by, String comment) { + Tombstone ts = addTombstone(source, entry); + ts.setWhen(when); + return ts; + } + + public static Tombstone addTombstone(Feed source, Entry entry, Calendar when, String by, String comment) { + Tombstone ts = addTombstone(source, entry); + ts.setWhen(when); + ts.setBy(by); + ts.setComment(comment); + return ts; + } + + public static Tombstone addTombstone(Feed source, Entry entry, long when, String by, String comment) { + Tombstone ts = addTombstone(source, entry); + ts.setWhen(when); + ts.setBy(by); + ts.setComment(comment); + return ts; + } + + public static Tombstone addTombstone(Feed source, Entry entry, DateTime when, String by, String comment) { + Tombstone ts = addTombstone(source, entry); + ts.setWhen(when); + ts.setBy(by); + ts.setComment(comment); + return ts; + + } + + public static boolean hasTombstones(Feed source) { + return source.getExtension(DELETED_ENTRY) != null; + } + + public static Tombstone addTombstone(Feed source, String id) { + Tombstone tombstone = source.getFactory().newExtensionElement(DELETED_ENTRY); + tombstone.setRef(id); + return tombstone; + } + + public static Tombstone addTombstone(Feed source, String id, Date when, String by, String comment) { + Tombstone ts = addTombstone(source, id); + ts.setWhen(when); + ts.setBy(by); + ts.setComment(comment); + return ts; + } + + public static Tombstone addTombstone(Feed source, String id, String when, String by, String comment) { + Tombstone ts = addTombstone(source, id); + ts.setWhen(when); + return ts; + } + + public static Tombstone addTombstone(Feed source, String id, Calendar when, String by, String comment) { + Tombstone ts = addTombstone(source, id); + ts.setWhen(when); + ts.setBy(by); + ts.setComment(comment); + return ts; + } + + public static Tombstone addTombstone(Feed source, String id, long when, String by, String comment) { + Tombstone ts = addTombstone(source, id); + ts.setWhen(when); + ts.setBy(by); + ts.setComment(comment); + return ts; + } + + public static Tombstone addTombstone(Feed source, String id, DateTime when, String by, String comment) { + Tombstone ts = addTombstone(source, id); + ts.setWhen(when); + ts.setBy(by); + ts.setComment(comment); + return ts; + } + +} Propchange: abdera/abdera2/ext/src/main/java/org/apache/abdera2/ext/tombstones/TombstonesHelper.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/resources/META-INF/MANIFEST.MF URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/resources/META-INF/MANIFEST.MF?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/resources/META-INF/MANIFEST.MF (added) +++ abdera/abdera2/ext/src/main/resources/META-INF/MANIFEST.MF Tue Sep 20 15:56:46 2011 @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + Propchange: abdera/abdera2/ext/src/main/resources/META-INF/MANIFEST.MF ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.factory.ExtensionFactory URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.factory.ExtensionFactory?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.factory.ExtensionFactory (added) +++ abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.factory.ExtensionFactory Tue Sep 20 15:56:46 2011 @@ -0,0 +1,7 @@ +org.apache.abdera2.ext.thread.ThreadExtensionFactory +org.apache.abdera2.ext.features.FeaturesExtensionFactory +org.apache.abdera2.ext.tombstones.TombstonesExtensionFactory +org.apache.abdera2.ext.media.MediaExtensionFactory +org.apache.abdera2.ext.opensearch.model.OpenSearchExtensionFactory +org.apache.abdera2.ext.sharing.SharingExtensionFactory +org.apache.abdera2.ext.rss.RssExtensionFactory \ No newline at end of file Added: abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.parser.Parser URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.parser.Parser?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.parser.Parser (added) +++ abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.parser.Parser Tue Sep 20 15:56:46 2011 @@ -0,0 +1 @@ +org.apache.abdera2.ext.html.HtmlParser \ No newline at end of file Added: abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.writer.Writer URL: http://svn.apache.org/viewvc/abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.writer.Writer?rev=1173209&view=auto ============================================================================== --- abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.writer.Writer (added) +++ abdera/abdera2/ext/src/main/resources/META-INF/services/org.apache.abdera2.writer.Writer Tue Sep 20 15:56:46 2011 @@ -0,0 +1 @@ +org.apache.abdera2.ext.json.JSONWriter \ No newline at end of file