/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Thierry Delprat */ package org.eclipse.ecr.core.event.jms; import java.io.Serializable; import java.rmi.dgc.VMID; import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.ecr.core.api.ClientException; import org.eclipse.ecr.core.api.CoreSession; import org.eclipse.ecr.core.api.DocumentModel; import org.eclipse.ecr.core.api.DocumentRef; import org.eclipse.ecr.core.api.IdRef; import org.eclipse.ecr.core.api.PathRef; import org.eclipse.ecr.core.api.SimplePrincipal; import org.eclipse.ecr.core.api.impl.DocumentModelImpl; import org.eclipse.ecr.core.event.Event; import org.eclipse.ecr.core.event.EventBundle; import org.eclipse.ecr.core.event.EventContext; import org.eclipse.ecr.core.event.impl.DocumentEventContext; import org.eclipse.ecr.core.event.impl.EventBundleImpl; import org.eclipse.ecr.core.event.impl.EventContextImpl; import org.eclipse.ecr.core.event.impl.EventImpl; import org.nuxeo.common.utils.Path; /** * Serializable representation of an {@link EventBundle} that is used for JMS * forwarding. * * @author Thierry Delprat */ public class SerializableEventBundle implements Serializable { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(SerializableEventBundle.class); protected final List<Map<String, Serializable>> serialisableEvents; protected final String eventBundleName; protected final VMID sourceVMID; protected boolean isDocumentEventContext = false; protected String coreInstanceName; public SerializableEventBundle(EventBundle events) { eventBundleName = events.getName(); sourceVMID = events.getSourceVMID(); serialisableEvents = new ArrayList<Map<String, Serializable>>(); for (Event event : events) { if (event.isLocal()) { // local event should not be exported to JMS continue; } CoreSession evtSession = event.getContext().getCoreSession(); String repoName = null; if (evtSession != null) { repoName = evtSession.getRepositoryName(); if (coreInstanceName == null) { coreInstanceName = repoName; } } Map<String, Serializable> serializableEvent = new HashMap<String, Serializable>(); serializableEvent.put("name", event.getName()); serializableEvent.put("time", Long.toString(event.getTime())); serializableEvent.put("contextProperties", (Serializable) event.getContext().getProperties()); if (evtSession != null) { serializableEvent.put("contextSessionId", evtSession.getSessionId()); } serializableEvent.put("principal", event.getContext().getPrincipal().getName()); serializableEvent.put("contextSessionRepositoryName", repoName); if (event.getContext() instanceof DocumentEventContext) { serializableEvent.put("isDocumentEventContext", true); } else { serializableEvent.put("isDocumentEventContext", false); } Object[] args = event.getContext().getArguments(); List<Serializable> listArgs = new ArrayList<Serializable>(); for (Object arg : args) { if (arg instanceof DocumentModel) { DocumentModel doc = (DocumentModel) arg; String strRepresentation = doc.getRepositoryName() + ":" + doc.getId() + ":" + doc.getType() + ":" + doc.getPathAsString(); listArgs.add("DOCREF:" + strRepresentation); } else if (arg instanceof Serializable) { log.debug("Adding serializable argument of class " + arg.getClass().getCanonicalName()); listArgs.add((Serializable) arg); } else { listArgs.add(null); } } serializableEvent.put("args", (Serializable) listArgs); serialisableEvents.add(serializableEvent); } } // Should not be necessary since this is noww done in CoreSession protected Map<String, Serializable> filterContextProperties( Map<String, Serializable> properties) { Map<String, Serializable> serializableProps = new HashMap<String, Serializable>(); for (String key : properties.keySet()) { Object value = properties.get(key); if (value instanceof Serializable) { Serializable serializableValue = (Serializable) value; serializableProps.put(key, serializableValue); } else { log.error("ContextMap contains non serializable object under key " + key); } } return serializableProps; } public VMID getSourceVMID() { return sourceVMID; } public String getEventBundleName() { return eventBundleName; } public String getCoreInstanceName() { return coreInstanceName; } public class EventBundleRelayedViaJMS extends EventBundleImpl { private static final long serialVersionUID = 1L; public EventBundleRelayedViaJMS() { // init VMID super(sourceVMID); } } @SuppressWarnings("unchecked") public EventBundle reconstructEventBundle(CoreSession session) throws CannotReconstruct { if (!session.getRepositoryName().equals(coreInstanceName)) { throw new CannotReconstruct( "This session can not be used on this Bundle"); } EventBundle bundle = new EventBundleRelayedViaJMS(); if (serialisableEvents == null) { return null; } for (Map<String, Serializable> evt : serialisableEvents) { String eventName = (String) evt.get("name"); Long time = Long.parseLong((String) evt.get("time")); Map<String, Serializable> ctxProperties = (Map<String, Serializable>) evt.get("contextProperties"); Principal principal = new SimplePrincipal( (String) evt.get("principal")); List<Serializable> listArgs = (List<Serializable>) evt.get("args"); Object[] args = new Object[listArgs.size()]; int idx = 0; for (Serializable sArg : listArgs) { Object value; if (sArg == null) { value = null; } else if (sArg instanceof String) { String arg = (String) sArg; if (arg.startsWith("DOCREF:")) { String[] part = arg.split(":"); DocumentRef idRef = new IdRef(part[2]); DocumentModel doc = null; try { if (session != null && session.exists(idRef)) { doc = session.getDocument(idRef); } else { String parentPath = new Path(part[4]).removeLastSegments( 1).toString(); doc = new DocumentModelImpl( session.getSessionId(), part[3], part[2], new Path(part[4]), null, idRef, new PathRef(parentPath), null, null, null, null); } } catch (ClientException e) { // TODO } value = doc; } else { value = arg; } } else { value = sArg; } args[idx] = value; idx++; } EventContext ctx; if ((Boolean) evt.get("isDocumentEventContext")) { ctx = new DocumentEventContext(session, principal, (DocumentModel) args[0], (DocumentRef) args[1]); // XXX we loose other args ... } else { ctx = new EventContextImpl(session, principal); ((EventContextImpl) ctx).setArgs(args); } ctx.setProperties(ctxProperties); Event e = new EventImpl(eventName, ctx, Event.FLAG_NONE, time); bundle.push(e); } return bundle; } public static class CannotReconstruct extends ClientException { private static final long serialVersionUID = 1L; public CannotReconstruct(String message) { super(message); } } }