001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Thierry Delprat 011 */ 012 013package org.nuxeo.ecm.core.event.jms; 014 015import java.io.Serializable; 016import java.rmi.dgc.VMID; 017import java.security.Principal; 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025import org.nuxeo.common.utils.Path; 026import org.nuxeo.ecm.core.api.CoreSession; 027import org.nuxeo.ecm.core.api.DocumentModel; 028import org.nuxeo.ecm.core.api.DocumentRef; 029import org.nuxeo.ecm.core.api.IdRef; 030import org.nuxeo.ecm.core.api.NuxeoException; 031import org.nuxeo.ecm.core.api.PathRef; 032import org.nuxeo.ecm.core.api.SimplePrincipal; 033import org.nuxeo.ecm.core.api.impl.DocumentModelImpl; 034import org.nuxeo.ecm.core.event.Event; 035import org.nuxeo.ecm.core.event.EventBundle; 036import org.nuxeo.ecm.core.event.EventContext; 037import org.nuxeo.ecm.core.event.impl.DocumentEventContext; 038import org.nuxeo.ecm.core.event.impl.EventBundleImpl; 039import org.nuxeo.ecm.core.event.impl.EventContextImpl; 040import org.nuxeo.ecm.core.event.impl.EventImpl; 041 042/** 043 * Serializable representation of an {@link EventBundle} that is used for JMS forwarding. 044 * 045 * @author Thierry Delprat 046 */ 047public class SerializableEventBundle implements Serializable { 048 049 private static final long serialVersionUID = 1L; 050 051 private static final Log log = LogFactory.getLog(SerializableEventBundle.class); 052 053 protected final List<Map<String, Serializable>> serialisableEvents; 054 055 protected final String eventBundleName; 056 057 protected final VMID sourceVMID; 058 059 protected boolean isDocumentEventContext = false; 060 061 protected String coreInstanceName; 062 063 public SerializableEventBundle(EventBundle events) { 064 eventBundleName = events.getName(); 065 sourceVMID = events.getSourceVMID(); 066 serialisableEvents = new ArrayList<Map<String, Serializable>>(); 067 068 for (Event event : events) { 069 if (event.isLocal()) { 070 // local event should not be exported to JMS 071 continue; 072 } 073 CoreSession evtSession = event.getContext().getCoreSession(); 074 075 String repoName = null; 076 if (evtSession != null) { 077 repoName = evtSession.getRepositoryName(); 078 if (coreInstanceName == null) { 079 coreInstanceName = repoName; 080 } 081 } 082 083 Map<String, Serializable> serializableEvent = new HashMap<String, Serializable>(); 084 085 serializableEvent.put("name", event.getName()); 086 serializableEvent.put("time", Long.toString(event.getTime())); 087 serializableEvent.put("contextProperties", (Serializable) event.getContext().getProperties()); 088 if (evtSession != null) { 089 serializableEvent.put("contextSessionId", evtSession.getSessionId()); 090 } 091 serializableEvent.put("principal", event.getContext().getPrincipal().getName()); 092 093 serializableEvent.put("contextSessionRepositoryName", repoName); 094 095 if (event.getContext() instanceof DocumentEventContext) { 096 serializableEvent.put("isDocumentEventContext", true); 097 } else { 098 serializableEvent.put("isDocumentEventContext", false); 099 } 100 101 Object[] args = event.getContext().getArguments(); 102 List<Serializable> listArgs = new ArrayList<Serializable>(); 103 for (Object arg : args) { 104 if (arg instanceof DocumentModel) { 105 DocumentModel doc = (DocumentModel) arg; 106 String strRepresentation = doc.getRepositoryName() + ":" + doc.getId() + ":" + doc.getType() + ":" 107 + doc.getPathAsString(); 108 listArgs.add("DOCREF:" + strRepresentation); 109 } else if (arg instanceof Serializable) { 110 log.debug("Adding serializable argument of class " + arg.getClass().getCanonicalName()); 111 listArgs.add((Serializable) arg); 112 } else { 113 listArgs.add(null); 114 } 115 } 116 117 serializableEvent.put("args", (Serializable) listArgs); 118 serialisableEvents.add(serializableEvent); 119 } 120 } 121 122 // Should not be necessary since this is noww done in CoreSession 123 protected Map<String, Serializable> filterContextProperties(Map<String, Serializable> properties) { 124 Map<String, Serializable> serializableProps = new HashMap<String, Serializable>(); 125 126 for (String key : properties.keySet()) { 127 Object value = properties.get(key); 128 if (value instanceof Serializable) { 129 Serializable serializableValue = (Serializable) value; 130 serializableProps.put(key, serializableValue); 131 } else { 132 log.error("ContextMap contains non serializable object under key " + key); 133 } 134 } 135 return serializableProps; 136 } 137 138 public VMID getSourceVMID() { 139 return sourceVMID; 140 } 141 142 public String getEventBundleName() { 143 return eventBundleName; 144 } 145 146 public String getCoreInstanceName() { 147 return coreInstanceName; 148 } 149 150 public class EventBundleRelayedViaJMS extends EventBundleImpl { 151 private static final long serialVersionUID = 1L; 152 153 public EventBundleRelayedViaJMS() { 154 // init VMID 155 super(sourceVMID); 156 } 157 } 158 159 @SuppressWarnings("unchecked") 160 public EventBundle reconstructEventBundle(CoreSession session) throws CannotReconstruct { 161 162 if (!session.getRepositoryName().equals(coreInstanceName)) { 163 throw new CannotReconstruct("This session can not be used on this Bundle"); 164 } 165 EventBundle bundle = new EventBundleRelayedViaJMS(); 166 167 if (serialisableEvents == null) { 168 return null; 169 } 170 171 for (Map<String, Serializable> evt : serialisableEvents) { 172 173 String eventName = (String) evt.get("name"); 174 Long time = Long.parseLong((String) evt.get("time")); 175 176 Map<String, Serializable> ctxProperties = (Map<String, Serializable>) evt.get("contextProperties"); 177 Principal principal = new SimplePrincipal((String) evt.get("principal")); 178 179 List<Serializable> listArgs = (List<Serializable>) evt.get("args"); 180 181 Object[] args = new Object[listArgs.size()]; 182 183 int idx = 0; 184 for (Serializable sArg : listArgs) { 185 Object value; 186 if (sArg == null) { 187 value = null; 188 } else if (sArg instanceof String) { 189 String arg = (String) sArg; 190 if (arg.startsWith("DOCREF:")) { 191 String[] part = arg.split(":"); 192 DocumentRef idRef = new IdRef(part[2]); 193 DocumentModel doc = null; 194 if (session != null && session.exists(idRef)) { 195 doc = session.getDocument(idRef); 196 } else { 197 String parentPath = new Path(part[4]).removeLastSegments(1).toString(); 198 doc = new DocumentModelImpl(session.getSessionId(), part[3], part[2], new Path(part[4]), 199 null, idRef, new PathRef(parentPath), null, null, null, null); 200 } 201 value = doc; 202 } else { 203 value = arg; 204 } 205 } else { 206 value = sArg; 207 } 208 args[idx] = value; 209 idx++; 210 } 211 212 EventContext ctx; 213 if ((Boolean) evt.get("isDocumentEventContext")) { 214 ctx = new DocumentEventContext(session, principal, (DocumentModel) args[0], (DocumentRef) args[1]); 215 // XXX we loose other args ... 216 } else { 217 ctx = new EventContextImpl(session, principal); 218 ((EventContextImpl) ctx).setArgs(args); 219 } 220 221 ctx.setProperties(ctxProperties); 222 Event e = new EventImpl(eventName, ctx, Event.FLAG_NONE, time); 223 bundle.push(e); 224 } 225 return bundle; 226 } 227 228 public static class CannotReconstruct extends NuxeoException { 229 230 private static final long serialVersionUID = 1L; 231 232 public CannotReconstruct(String message) { 233 super(message); 234 } 235 236 } 237 238}