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-94f89814c4df
master
jensp 2012-03-19 12:49:10 +00:00
parent b00e272ffa
commit 451b67580d
7 changed files with 419 additions and 36 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -1144,6 +1144,7 @@ public class ContentItem extends VersionedACSObject implements CustomCopy {
oldVersion.delete();
PublishedLink.refreshOnUnpublish(this);
PublishedAssociation.refreshOnUnPublish(this);
}
if (parent instanceof ContentBundle || parent instanceof Folder) {
@ -1172,6 +1173,7 @@ public class ContentItem extends VersionedACSObject implements CustomCopy {
save();
PublishedLink.updateLiveLinks(version);
PublishedAssociation.updateLiveAssoications(version);
save();
// publish item (as template or html pages) to the file

View 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());
}
}
}
}
}
}

View File

@ -34,6 +34,7 @@ import com.arsdigita.persistence.SessionManager;
import com.arsdigita.persistence.metadata.ObjectType;
import com.arsdigita.persistence.metadata.Property;
import com.arsdigita.util.Assert;
import com.arsdigita.util.UncheckedWrapperException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -378,6 +379,7 @@ class PublishedLink extends DomainObject {
ObjectOutputStream out = new ObjectOutputStream(data);
out.writeObject(linkAttributes);
} catch (IOException ex) {
throw new UncheckedWrapperException(ex);
}
set(LINK_ATTRIBUTES, data.toByteArray());

View File

@ -196,6 +196,14 @@ class VersionCopier extends ObjectCopier {
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()) {
s_log.debug("The property is a component; creating a "
+ "live or pending version");
@ -238,6 +246,7 @@ class VersionCopier extends ObjectCopier {
return null;
}
}
} else {
s_log.debug("The property is not a content item; using "
+ "domain object copier");