001/*
002 * (C) Copyright 2016 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 *     bdelbosc
018 */
019package org.nuxeo.importer.stream.message;
020
021import java.io.IOException;
022import java.io.ObjectInput;
023import java.io.ObjectOutput;
024import java.io.Serializable;
025import java.util.Collections;
026import java.util.HashMap;
027import java.util.Map;
028
029import org.nuxeo.ecm.core.api.Blob;
030import org.nuxeo.ecm.core.blob.BlobInfo;
031import org.nuxeo.lib.stream.pattern.Message;
032
033/**
034 * Message that represent an immutable Nuxeo document.
035 *
036 * @since 9.1
037 */
038public class DocumentMessage implements Message {
039    static final long serialVersionUID = 20170529L;
040
041    protected String type;
042
043    protected String parentPath;
044
045    protected String name;
046
047    protected Map<String, Serializable> properties;
048
049    protected Blob blob;
050
051    protected BlobInfo blobInfo;
052
053    public DocumentMessage() {
054    }
055
056    protected DocumentMessage(Builder builder) {
057        type = builder.type;
058        parentPath = builder.parentPath;
059        name = builder.name;
060        properties = builder.properties;
061        blob = builder.blob;
062        blobInfo = builder.blobInfo;
063    }
064
065    public String getName() {
066        return name;
067    }
068
069    @Override
070    public String getId() {
071        return parentPath + "/" + name;
072    }
073
074    /**
075     * Type of the document
076     */
077    public String getType() {
078        return type;
079    }
080
081    public String getParentPath() {
082        return parentPath;
083    }
084
085    public Map<String, Serializable> getProperties() {
086        return Collections.unmodifiableMap(properties);
087    }
088
089    public Blob getBlob() {
090        // should return unmodifiable blob
091        return blob;
092    }
093
094    public BlobInfo getBlobInfo() {
095        return blobInfo;
096    }
097
098    /**
099     * Helper to build a document message.
100     *
101     * @param type the type of document
102     * @param parentPath the container path where the document should be created
103     * @param name the name of the document
104     */
105    public static Builder builder(String type, String parentPath, String name) {
106        return new Builder(type, parentPath, name);
107    }
108
109    public static DocumentMessage copy(DocumentMessage node, String newName) {
110        Builder builder = builder(node.type, node.parentPath, newName);
111        builder.blob = node.blob;
112        builder.blobInfo = node.blobInfo;
113        builder.properties = node.properties;
114        return builder.build();
115    }
116
117    public static class Builder {
118        protected String name;
119
120        protected String parentPath;
121
122        protected String type;
123
124        protected Map<String, Serializable> properties;
125
126        protected Blob blob;
127
128        protected BlobInfo blobInfo;
129
130        protected Builder(String type, String parentPath, String name) {
131            this.type = type;
132            this.parentPath = parentPath;
133            this.name = name;
134        }
135
136        @SuppressWarnings("unchecked")
137        public Builder setProperties(HashMap<String, Serializable> properties) {
138            this.properties = (Map) properties.clone();
139            return this;
140        }
141
142        public Builder setBlob(Blob blob) {
143            this.blob = blob;
144            return this;
145        }
146
147        public Builder setBlobInfo(BlobInfo blobInfo) {
148            this.blobInfo = new BlobInfo(blobInfo);
149            return this;
150        }
151
152        public String getName() {
153            return name;
154        }
155
156        public String getParentPath() {
157            return parentPath;
158        }
159
160        public String getType() {
161            return type;
162        }
163
164        public void setName(String name) {
165            this.name = name;
166        }
167
168        public void setParentPath(String parentPath) {
169            this.parentPath = parentPath;
170        }
171
172        public void setType(String type) {
173            this.type = type;
174        }
175
176        public Map<String, Serializable> getProperties() {
177            return properties;
178        }
179
180        public DocumentMessage build() {
181            return new DocumentMessage(this);
182        }
183    }
184
185    @Override
186    public void writeExternal(ObjectOutput out) throws IOException {
187        out.writeObject(type);
188        out.writeObject(parentPath);
189        out.writeObject(name);
190        int nbProperties = (properties == null ? 0 : properties.size());
191        out.writeInt(nbProperties);
192        if (properties != null) {
193            for (Map.Entry<String, Serializable> entry : properties.entrySet()) {
194                out.writeObject(entry.getKey());
195                out.writeObject(entry.getValue());
196            }
197        }
198        if (blob != null) {
199            out.writeBoolean(true);
200            out.writeObject(blob);
201        } else {
202            out.writeBoolean(false);
203        }
204        if (blobInfo != null) {
205            out.writeBoolean(true);
206            out.writeObject(blobInfo.key);
207            out.writeObject(blobInfo.digest);
208            out.writeLong(blobInfo.length);
209            out.writeObject(blobInfo.filename);
210            out.writeObject(blobInfo.encoding);
211            out.writeObject(blobInfo.mimeType);
212        } else {
213            out.writeBoolean(false);
214        }
215    }
216
217    @Override
218    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
219        type = (String) in.readObject();
220        parentPath = (String) in.readObject();
221        name = (String) in.readObject();
222        int nbProperties = in.readInt();
223        if (nbProperties > 0) {
224            properties = new HashMap<>(nbProperties);
225            while (nbProperties > 0) {
226                String key = (String) in.readObject();
227                Serializable value = (Serializable) in.readObject();
228                properties.put(key, value);
229                nbProperties--;
230            }
231        }
232        if (in.readBoolean()) {
233            blob = (Blob) in.readObject();
234        }
235        if (in.readBoolean()) {
236            blobInfo = new BlobInfo();
237            blobInfo.key = (String) in.readObject();
238            blobInfo.digest = (String) in.readObject();
239            blobInfo.length = in.readLong();
240            blobInfo.filename = (String) in.readObject();
241            blobInfo.encoding = (String) in.readObject();
242            blobInfo.mimeType = (String) in.readObject();
243        }
244
245    }
246
247    @Override
248    public String toString() {
249        String bi = "";
250        if (blobInfo != null) {
251            bi = String.format("blobInfo(key=%s filename=%s)", blobInfo.key, blobInfo.filename);
252        } else if (blob != null) {
253            bi = String.format("blob(filename=%s)", blob.getFilename());
254        }
255        return String.format("DocumentMessage(type=%s name=%s parentPath=%s bi=%s)", type, name, parentPath, bi);
256    }
257    // TODO: impl hashCode, equals, toString
258}