001/*
002 * (C) Copyright 2006-2009 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo
018 */
019
020package org.nuxeo.ecm.platform.publisher.remoting.marshaling;
021
022import org.dom4j.Document;
023import org.dom4j.DocumentException;
024import org.dom4j.DocumentFactory;
025import org.dom4j.DocumentHelper;
026import org.dom4j.QName;
027import org.nuxeo.ecm.core.api.CoreSession;
028import org.nuxeo.ecm.core.api.DocumentLocation;
029import org.nuxeo.ecm.core.api.DocumentModel;
030import org.nuxeo.ecm.core.api.NuxeoException;
031import org.nuxeo.ecm.platform.publisher.api.PublicationNode;
032import org.nuxeo.ecm.platform.publisher.api.PublishedDocument;
033import org.nuxeo.ecm.platform.publisher.remoting.marshaling.interfaces.DocumentLocationMarshaler;
034import org.nuxeo.ecm.platform.publisher.remoting.marshaling.interfaces.DocumentModelMarshaler;
035import org.nuxeo.ecm.platform.publisher.remoting.marshaling.interfaces.PublicationNodeMarshaler;
036import org.nuxeo.ecm.platform.publisher.remoting.marshaling.interfaces.PublishedDocumentMarshaler;
037import org.nuxeo.ecm.platform.publisher.remoting.marshaling.interfaces.RemotePublisherMarshaler;
038
039import java.util.ArrayList;
040import java.util.HashMap;
041import java.util.Iterator;
042import java.util.List;
043import java.util.Map;
044
045/**
046 * Default marshaler for RPC calls between 2 servers
047 *
048 * @author tiry
049 */
050public class DefaultMarshaler extends AbstractDefaultXMLMarshaler implements RemotePublisherMarshaler {
051
052    private static final String PARAM_PATTERN = "$PARAM";
053
054    private static final String RESULT_PATTERN = "$RESULT$";
055
056    protected PublicationNodeMarshaler nodeMarshaler;
057
058    protected PublishedDocumentMarshaler publishedDocumentMarshaler;
059
060    protected DocumentModelMarshaler documentModelMarshaler;
061
062    protected DocumentLocationMarshaler docLocMarshaler;
063
064    protected Map<String, String> params = new HashMap<String, String>();
065
066    protected static QName rootParametersTag = DocumentFactory.getInstance().createQName("parameters",
067            publisherSerializerNSPrefix, publisherSerializerNS);
068
069    protected static QName parameterTag = DocumentFactory.getInstance().createQName("parameter",
070            publisherSerializerNSPrefix, publisherSerializerNS);
071
072    protected static QName rootResultTag = DocumentFactory.getInstance().createQName("result",
073            publisherSerializerNSPrefix, publisherSerializerNS);
074
075    protected CoreSession session;
076
077    public DefaultMarshaler() {
078        this(null);
079    }
080
081    public DefaultMarshaler(CoreSession session) {
082        this.nodeMarshaler = new DefaultPublicationNodeMarshaler();
083        this.publishedDocumentMarshaler = new DefaultPublishedDocumentMarshaler();
084        this.documentModelMarshaler = new CoreIODocumentModelMarshaler();
085        this.docLocMarshaler = new DefaultDocumentLocationMarshaler();
086        this.session = session;
087    }
088
089    public String marshallParameters(List<Object> params) {
090
091        if (params == null) {
092            return "null";
093        }
094        String env = buildParameterEnvelope(params.size());
095        int idx = 1;
096        for (Object param : params) {
097            String strParam = marshalSingleObject(param);
098            env = env.replace(PARAM_PATTERN + idx + "$", strParam);
099            idx += 1;
100        }
101        return env;
102    }
103
104    public String marshallResult(Object result) {
105        String res = buildResultEnvelope();
106        String strResult = marshalSingleObject(result);
107        res = res.replace(RESULT_PATTERN, strResult);
108        return res;
109    }
110
111    public List<Object> unMarshallParameters(String data) {
112        return unMarshallParameters(data, session);
113    }
114
115    protected List<Object> unMarshallParameters(String data, CoreSession session) {
116
117        List<Object> params = new ArrayList<Object>();
118
119        Document document;
120        try {
121            document = DocumentHelper.parseText(data);
122            org.dom4j.Element rootElem = document.getRootElement();
123            for (Iterator i = rootElem.elementIterator(parameterTag); i.hasNext();) {
124                org.dom4j.Element param = (org.dom4j.Element) i.next();
125                if (param.elements().size() > 0) {
126                    String xmlParam = ((org.dom4j.Element) param.elements().get(0)).asXML();
127                    params.add(unMarshalSingleObject(xmlParam, session));
128                } else {
129                    String value = param.getText();
130                    if ("null".equals(value)) {
131                        value = null;
132                    }
133                    params.add(value);
134                }
135            }
136        } catch (DocumentException e) {
137            throw new NuxeoException("Error during unmarshaling of parameters", e);
138        }
139        return params;
140    }
141
142    public Object unMarshallResult(String data) {
143        return unMarshallResult(data, session);
144    }
145
146    protected Object unMarshallResult(String data, CoreSession coreSession) {
147        Document document;
148        try {
149            document = DocumentHelper.parseText(data);
150            org.dom4j.Element rootElem = document.getRootElement();
151
152            if (rootElem.elements().size() == 0) {
153                return rootElem.getText();
154            } else {
155                return unMarshalSingleObject(((org.dom4j.Element) rootElem.elements().get(0)).asXML(), coreSession);
156            }
157        } catch (DocumentException e) {
158            throw new NuxeoException("Error during unmarshaling Result", e);
159        }
160    }
161
162    protected String buildParameterEnvelope(int nbParams) {
163
164        org.dom4j.Element rootElem = DocumentFactory.getInstance().createElement(rootParametersTag);
165        rootElem.addNamespace(publisherSerializerNSPrefix, publisherSerializerNS);
166        org.dom4j.Document rootDoc = DocumentFactory.getInstance().createDocument(rootElem);
167
168        for (int i = 1; i <= nbParams; i++) {
169            org.dom4j.Element pathElem = rootElem.addElement(parameterTag);
170            pathElem.setText(PARAM_PATTERN + i + "$");
171        }
172        return rootDoc.asXML();
173    }
174
175    protected String buildResultEnvelope() {
176
177        org.dom4j.Element rootElem = DocumentFactory.getInstance().createElement(rootResultTag);
178        rootElem.addNamespace(publisherSerializerNSPrefix, publisherSerializerNS);
179        org.dom4j.Document rootDoc = DocumentFactory.getInstance().createDocument(rootElem);
180        rootElem.setText(RESULT_PATTERN);
181        return rootDoc.asXML();
182    }
183
184    protected Object unMarshalSingleObject(String xml, CoreSession coreSession) {
185        Document document;
186        try {
187            document = DocumentHelper.parseText(xml);
188        } catch (DocumentException e) {
189            throw new NuxeoException("Error during unmarshaling", e);
190        }
191        org.dom4j.Element rootElem = document.getRootElement();
192
193        QName qname = rootElem.getQName();
194        String name = rootElem.getName();
195
196        if (name.equals("publicationNode")) {
197            return nodeMarshaler.unMarshalPublicationNode(xml);
198        } else if (name.equals("publishedDocument")) {
199            return publishedDocumentMarshaler.unMarshalPublishedDocument(xml);
200        } else if (name.equals("document")) {
201            return documentModelMarshaler.unMarshalDocument(xml, coreSession);
202        } else if (name.equals("documentLocation")) {
203            return docLocMarshaler.unMarshalDocumentLocation(xml);
204        } else if (name.equals("list")) {
205            List<Object> lst = new ArrayList<Object>();
206            for (Iterator i = rootElem.elementIterator("listitem"); i.hasNext();) {
207                org.dom4j.Element el = (org.dom4j.Element) i.next();
208                if (el.elements().size() == 0) {
209                    lst.add(el.getText());
210                } else {
211                    lst.add(unMarshalSingleObject(((org.dom4j.Element) el.elements().get(0)).asXML(), coreSession));
212                }
213            }
214            return lst;
215        } else if (name.equals("map")) {
216            Map map = new HashMap();
217            for (Iterator i = rootElem.elementIterator("mapitem"); i.hasNext();) {
218                org.dom4j.Element el = (org.dom4j.Element) i.next();
219
220                Object value = null;
221                if (el.elements().size() > 0) {
222                    value = unMarshalSingleObject(((org.dom4j.Element) (el).elements().get(0)).asXML(), coreSession);
223                } else {
224                    value = el.getText();
225                }
226                String key = el.attributeValue("name");
227                map.put(key, value);
228            }
229            return map;
230        }
231
232        throw new NuxeoException("Unable to unmarshal data");
233
234    }
235
236    protected String marshalSingleObject(Object ob) {
237        if (ob == null) {
238            return "null";
239        } else if (ob instanceof String) {
240            return (String) ob;
241        } else if (ob instanceof DocumentModel) {
242            return cleanUpXml(documentModelMarshaler.marshalDocument((DocumentModel) ob));
243        } else if (ob instanceof PublicationNode) {
244            return nodeMarshaler.marshalPublicationNode((PublicationNode) ob);
245        } else if (ob instanceof PublishedDocument) {
246            return publishedDocumentMarshaler.marshalPublishedDocument((PublishedDocument) ob);
247        } else if (ob instanceof DocumentLocation) {
248            return docLocMarshaler.marshalDocumentLocation((DocumentLocation) ob);
249        } else if (ob instanceof List) {
250            StringBuffer sb = new StringBuffer();
251            sb.append("<list>");
252
253            List list = (List) ob;
254            for (Object itemOb : list) {
255                sb.append("<listitem>");
256                sb.append(marshalSingleObject(itemOb));
257                sb.append("</listitem>");
258            }
259            sb.append("</list>");
260            return sb.toString();
261        } else if (ob instanceof Map) {
262            StringBuffer sb = new StringBuffer();
263            sb.append("<map>");
264            Map map = (Map) ob;
265            for (Object key : map.keySet()) {
266                sb.append("<mapitem ");
267                sb.append("name=\"");
268                sb.append((String) key);
269                sb.append("\">");
270                sb.append(marshalSingleObject(map.get(key)));
271                sb.append("</mapitem>");
272            }
273            sb.append("</map>");
274            return sb.toString();
275        }
276        throw new NuxeoException("unable to marshal object of class " + ob.getClass().getName());
277    }
278
279    public void setAssociatedCoreSession(CoreSession session) {
280        this.session = session;
281    }
282
283    public void setParameters(Map<String, String> params) {
284        this.params.putAll(params);
285        docLocMarshaler.setOriginatingServer(params.get("originalServer"));
286        documentModelMarshaler.setOriginatingServer(params.get("originalServer"));
287    }
288}