Neues Verfahren für das Publizieren von Assoziationen zwischen ContentItems. Noch nicht integriert.
git-svn-id: https://svn.libreccm.org/ccm/trunk@1543 8810af33-2d31-482b-a856-94f89814c4dfmaster
parent
b00e272ffa
commit
451b67580d
|
|
@ -0,0 +1,14 @@
|
||||||
|
//$Id$
|
||||||
|
|
||||||
|
model com.arsdigita.cms;
|
||||||
|
|
||||||
|
object type PublishedAssociation {
|
||||||
|
composite ContentItem[1..1] draftA = join cms_published_associations.draft_a to cms_items.item_id;
|
||||||
|
composite ContentItem[1..1] draftB = join cms_published_associations.draft_b to cms_items.item_id;
|
||||||
|
String[1..1] propertyA = cms_published_associations.property_a VARCHAR(100);
|
||||||
|
String[1..1] propertyB = cms_published_associations.property_b VARCHAR(100);
|
||||||
|
//composite ContentItem[1..1] pendingA = join cms_published_associations.pending_a to cms_items.item_id;
|
||||||
|
//composite ContentItem[1..1] pendingB = join cms_published_associations.pending_b to cms_items.item_id;
|
||||||
|
Blob[0..1] associationAttributes = cms_published_associations.association_attributes BLOB;
|
||||||
|
object key (draftA, draftB, propertyA, propertyB);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.arsdigita.cms;
|
||||||
|
|
||||||
|
import com.arsdigita.domain.DomainObject;
|
||||||
|
import com.arsdigita.persistence.metadata.Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Jens Pelzetter
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public interface AssociationCopier {
|
||||||
|
|
||||||
|
boolean handlesProperty(Property property);
|
||||||
|
void copy(DomainObject source,
|
||||||
|
DomainObject target,
|
||||||
|
DomainObject value,
|
||||||
|
Property property);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.arsdigita.cms;
|
||||||
|
|
||||||
|
import com.arsdigita.domain.DomainObject;
|
||||||
|
import com.arsdigita.persistence.metadata.Property;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Jens Pelzetter
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AssociationCopierDefaultImpl implements AssociationCopier {
|
||||||
|
|
||||||
|
final Map<String, HandledProperty> handledProperties =
|
||||||
|
new HashMap<String, HandledProperty>();
|
||||||
|
|
||||||
|
public void addHandledProperty(final String name,
|
||||||
|
final String type,
|
||||||
|
final String reverse,
|
||||||
|
final String reverseType) {
|
||||||
|
final HandledProperty prop = new HandledProperty();
|
||||||
|
prop.setName(name);
|
||||||
|
prop.setType(type);
|
||||||
|
prop.setReverse(reverse);
|
||||||
|
prop.setReverseType(reverseType);
|
||||||
|
handledProperties.put(name, prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean handlesProperty(final Property property) {
|
||||||
|
return handledProperties.containsKey(property.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copy(final DomainObject source,
|
||||||
|
final DomainObject target,
|
||||||
|
final DomainObject value,
|
||||||
|
final Property property) {
|
||||||
|
final HandledProperty propData = handledProperties.get(
|
||||||
|
property.getName());
|
||||||
|
if (propData == null) {
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"Illegal call for this method. Property '%s' is not handled"
|
||||||
|
+ "by this AssociationCopier.", property.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create PublishedAssociation here.
|
||||||
|
final HandledProperty handledProperty = handledProperties.get(property.
|
||||||
|
getName());
|
||||||
|
if (handledProperty == null) {
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"Property '%s' "
|
||||||
|
+ "is not handled by this AssociationCopier.",
|
||||||
|
property.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
final ContentItem sourceItem = (ContentItem) source;
|
||||||
|
final ContentItem valueItem = (ContentItem) value;
|
||||||
|
|
||||||
|
PublishedAssociation.create(sourceItem,
|
||||||
|
valueItem,
|
||||||
|
property.getName(),
|
||||||
|
handledProperty.getReverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class HandledProperty {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String type;
|
||||||
|
private String reverse;
|
||||||
|
private String reverseType;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReverse() {
|
||||||
|
return reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReverse(String reverse) {
|
||||||
|
this.reverse = reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReverseType() {
|
||||||
|
return reverseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReverseType(String reverseType) {
|
||||||
|
this.reverseType = reverseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1144,6 +1144,7 @@ public class ContentItem extends VersionedACSObject implements CustomCopy {
|
||||||
|
|
||||||
oldVersion.delete();
|
oldVersion.delete();
|
||||||
PublishedLink.refreshOnUnpublish(this);
|
PublishedLink.refreshOnUnpublish(this);
|
||||||
|
PublishedAssociation.refreshOnUnPublish(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent instanceof ContentBundle || parent instanceof Folder) {
|
if (parent instanceof ContentBundle || parent instanceof Folder) {
|
||||||
|
|
@ -1172,6 +1173,7 @@ public class ContentItem extends VersionedACSObject implements CustomCopy {
|
||||||
save();
|
save();
|
||||||
|
|
||||||
PublishedLink.updateLiveLinks(version);
|
PublishedLink.updateLiveLinks(version);
|
||||||
|
PublishedAssociation.updateLiveAssoications(version);
|
||||||
save();
|
save();
|
||||||
|
|
||||||
// publish item (as template or html pages) to the file
|
// publish item (as template or html pages) to the file
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,233 @@
|
||||||
|
package com.arsdigita.cms;
|
||||||
|
|
||||||
|
import com.arsdigita.domain.DomainObject;
|
||||||
|
import com.arsdigita.persistence.DataCollection;
|
||||||
|
import com.arsdigita.persistence.DataObject;
|
||||||
|
import com.arsdigita.persistence.OID;
|
||||||
|
import com.arsdigita.persistence.Session;
|
||||||
|
import com.arsdigita.persistence.SessionManager;
|
||||||
|
import com.arsdigita.persistence.metadata.Property;
|
||||||
|
import com.arsdigita.util.UncheckedWrapperException;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Jens Pelzetter
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class PublishedAssociation extends DomainObject {
|
||||||
|
|
||||||
|
private static final String DRAFT_A = "draftA";
|
||||||
|
private static final String DRAFT_B = "draftA";
|
||||||
|
private static final String PROPERTY_A = "propertyA";
|
||||||
|
private static final String PROPERTY_B = "propertyB";
|
||||||
|
//private static final String PENDING_A = "pendingA";
|
||||||
|
//private static final String PENDING_B = "pendingA";
|
||||||
|
private static final String ATTRIBUTES = "associationAttributes";
|
||||||
|
public static final String BASE_DATA_OBJECT_TYPE =
|
||||||
|
"com.arsdigita.cms.PublishedAssociation";
|
||||||
|
|
||||||
|
protected PublishedAssociation() {
|
||||||
|
super(BASE_DATA_OBJECT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PublishedAssociation(final DataObject dobj) {
|
||||||
|
super(dobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PublishedAssociation(final OID oid) {
|
||||||
|
super(oid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getBaseDataObjectType() {
|
||||||
|
return BASE_DATA_OBJECT_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static PublishedAssociation create(final ContentItem draftA,
|
||||||
|
final ContentItem draftB,
|
||||||
|
final String propertyA,
|
||||||
|
final String propertyB) {
|
||||||
|
//Check if the association is already saved.
|
||||||
|
final Session session = SessionManager.getSession();
|
||||||
|
final DataCollection assocsA = session.retrieve(BASE_DATA_OBJECT_TYPE);
|
||||||
|
assocsA.addEqualsFilter(DRAFT_A + ".id", draftA.getID());
|
||||||
|
assocsA.addEqualsFilter(DRAFT_B + ".id", draftB.getID());
|
||||||
|
assocsA.addEqualsFilter(PROPERTY_A, propertyA);
|
||||||
|
assocsA.addEqualsFilter(PROPERTY_B, propertyB);
|
||||||
|
|
||||||
|
if (assocsA.size() == 1) {
|
||||||
|
assocsA.next();
|
||||||
|
final DataObject dobj = assocsA.getDataObject();
|
||||||
|
assocsA.close();
|
||||||
|
return new PublishedAssociation(dobj);
|
||||||
|
} else if (assocsA.size() > 1) {
|
||||||
|
throw new UncheckedWrapperException(
|
||||||
|
"Something very strange has occurred. There is more than "
|
||||||
|
+ "one PublishedAssociation for a association.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Maybe draftA and draftB are switched
|
||||||
|
final DataCollection assocsB = session.retrieve(BASE_DATA_OBJECT_TYPE);
|
||||||
|
assocsB.addEqualsFilter(DRAFT_A + ".id", draftB.getID());
|
||||||
|
assocsB.addEqualsFilter(DRAFT_B + ".id", draftA.getID());
|
||||||
|
assocsB.addEqualsFilter(PROPERTY_A, propertyB);
|
||||||
|
assocsB.addEqualsFilter(PROPERTY_B, propertyA);
|
||||||
|
|
||||||
|
if (assocsB.size() == 1) {
|
||||||
|
assocsB.next();
|
||||||
|
final DataObject dobj = assocsB.getDataObject();
|
||||||
|
assocsB.close();
|
||||||
|
return new PublishedAssociation(dobj);
|
||||||
|
} else if (assocsB.size() > 1) {
|
||||||
|
throw new UncheckedWrapperException(
|
||||||
|
"Something very strange has occurred. There is more than "
|
||||||
|
+ "one PublishedAssociation for a association.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//No existing entry found, crate new one.
|
||||||
|
|
||||||
|
final PublishedAssociation assoc = new PublishedAssociation();
|
||||||
|
assoc.set(DRAFT_A, draftA);
|
||||||
|
assoc.set(DRAFT_B, draftB);
|
||||||
|
assoc.set(PROPERTY_A, propertyA);
|
||||||
|
assoc.set(PROPERTY_B, PROPERTY_B);
|
||||||
|
|
||||||
|
if (draftA.getObjectType().getProperty(propertyA).isCollection()) {
|
||||||
|
final DataCollection coll = (DataCollection) draftA.get(
|
||||||
|
propertyA + "@link");
|
||||||
|
|
||||||
|
while (coll.next()) {
|
||||||
|
DataObject linkObj = coll.getDataObject();
|
||||||
|
|
||||||
|
if (draftB.getOID().equals(((DataObject) linkObj.getOID().get(
|
||||||
|
propertyA)).getOID())) {
|
||||||
|
assoc.saveAssociationAttributes(linkObj);
|
||||||
|
coll.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assoc.save();
|
||||||
|
|
||||||
|
return assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void updateLiveAssociations(final ContentItem item) {
|
||||||
|
final Session session = SessionManager.getSession();
|
||||||
|
final ContentItem draftItem = item.getDraftVersion();
|
||||||
|
final ContentItem liveItem = draftItem.getLiveVersion();
|
||||||
|
|
||||||
|
final DataCollection assocsA = session.retrieve(BASE_DATA_OBJECT_TYPE);
|
||||||
|
assocsA.addEqualsFilter(DRAFT_A + ".id", draftItem.getID());
|
||||||
|
processAssociations(assocsA, liveItem);
|
||||||
|
|
||||||
|
final DataCollection assocsB = session.retrieve(BASE_DATA_OBJECT_TYPE);
|
||||||
|
assocsB.addEqualsFilter(DRAFT_B + ".id", draftItem.getID());
|
||||||
|
processAssociations(assocsB, liveItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void processAssociations(final DataCollection associations,
|
||||||
|
final ContentItem liveItem) {
|
||||||
|
while (associations.next()) {
|
||||||
|
processAssociation(new PublishedAssociation(
|
||||||
|
associations.getDataObject()), liveItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void processAssociation(
|
||||||
|
final PublishedAssociation association,
|
||||||
|
final ContentItem liveItem) {
|
||||||
|
final ContentItem otherDraft = (ContentItem) association.get(DRAFT_B);
|
||||||
|
final ContentItem otherLive = otherDraft.getLiveVersion();
|
||||||
|
|
||||||
|
if (otherLive != null) {
|
||||||
|
createAssociation(liveItem,
|
||||||
|
(String) association.get(PROPERTY_A),
|
||||||
|
otherLive,
|
||||||
|
(byte[]) association.get(ATTRIBUTES));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void createAssociation(final ContentItem itemA,
|
||||||
|
final String propertyA,
|
||||||
|
final ContentItem itemB,
|
||||||
|
final byte[] associationAttributes) {
|
||||||
|
final DataObject association = itemA.add(propertyA, itemB);
|
||||||
|
setAttributesForLiveAssociation(association, associationAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void refreshOnUnPublish(final ContentItem item) {
|
||||||
|
//Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveAssociationAttributes(final DataObject assocObj) {
|
||||||
|
final Iterator properties = assocObj.getObjectType().
|
||||||
|
getDeclaredProperties();
|
||||||
|
final Map<String, Object> assocAttrs = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
while (properties.hasNext()) {
|
||||||
|
processAttribute(assocObj, assocAttrs, (Property) properties.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!assocAttrs.isEmpty()) {
|
||||||
|
final ByteArrayOutputStream data = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
final ObjectOutputStream out = new ObjectOutputStream(data);
|
||||||
|
out.writeObject(assocAttrs);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
set(ATTRIBUTES, data.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processAttribute(final DataObject assocObj,
|
||||||
|
final Map<String, Object> assocAttrs,
|
||||||
|
final Property property) {
|
||||||
|
final String name = property.getName();
|
||||||
|
|
||||||
|
// Teste Property: Es darf kein Key und muß ein simples Attribute sein
|
||||||
|
if (property.isAttribute() && !property.isKeyProperty()) {
|
||||||
|
final Object value = assocObj.get(name);
|
||||||
|
assocAttrs.put(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setAttributesForLiveAssociation(
|
||||||
|
final DataObject association, byte[] attributes) {
|
||||||
|
if (attributes != null) {
|
||||||
|
final ByteArrayInputStream data;
|
||||||
|
final ObjectInputStream in;
|
||||||
|
final Map<String, Object> assocAttrs;
|
||||||
|
|
||||||
|
data = new ByteArrayInputStream(attributes);
|
||||||
|
try {
|
||||||
|
in = new ObjectInputStream(data);
|
||||||
|
assocAttrs = (Map<String, Object>) in.readObject();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assocAttrs != null) {
|
||||||
|
for(Map.Entry<String, Object> entry : assocAttrs.entrySet()) {
|
||||||
|
if(association.getObjectType().hasDeclaredProperty(entry.getKey())
|
||||||
|
&& association.getSession() != null) {
|
||||||
|
association.set(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -34,6 +34,7 @@ import com.arsdigita.persistence.SessionManager;
|
||||||
import com.arsdigita.persistence.metadata.ObjectType;
|
import com.arsdigita.persistence.metadata.ObjectType;
|
||||||
import com.arsdigita.persistence.metadata.Property;
|
import com.arsdigita.persistence.metadata.Property;
|
||||||
import com.arsdigita.util.Assert;
|
import com.arsdigita.util.Assert;
|
||||||
|
import com.arsdigita.util.UncheckedWrapperException;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -378,6 +379,7 @@ class PublishedLink extends DomainObject {
|
||||||
ObjectOutputStream out = new ObjectOutputStream(data);
|
ObjectOutputStream out = new ObjectOutputStream(data);
|
||||||
out.writeObject(linkAttributes);
|
out.writeObject(linkAttributes);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
set(LINK_ATTRIBUTES, data.toByteArray());
|
set(LINK_ATTRIBUTES, data.toByteArray());
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,14 @@ class VersionCopier extends ObjectCopier {
|
||||||
item.assertDraft();
|
item.assertDraft();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((item instanceof AssociationCopier)
|
||||||
|
&& ((AssociationCopier) item).handlesProperty(prop)) {
|
||||||
|
final AssociationCopier assocCopier = (AssociationCopier) item;
|
||||||
|
assocCopier.copy(source, target, target, prop);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
|
||||||
if (prop.isComponent()) {
|
if (prop.isComponent()) {
|
||||||
s_log.debug("The property is a component; creating a "
|
s_log.debug("The property is a component; creating a "
|
||||||
+ "live or pending version");
|
+ "live or pending version");
|
||||||
|
|
@ -238,6 +246,7 @@ class VersionCopier extends ObjectCopier {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
s_log.debug("The property is not a content item; using "
|
s_log.debug("The property is not a content item; using "
|
||||||
+ "domain object copier");
|
+ "domain object copier");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue