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 final String name;
119
120        protected final String parentPath;
121
122        protected final 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 Map<String, Serializable> getProperties() {
165            return properties;
166        }
167
168        public DocumentMessage build() {
169            return new DocumentMessage(this);
170        }
171    }
172
173    @Override
174    public void writeExternal(ObjectOutput out) throws IOException {
175        out.writeObject(type);
176        out.writeObject(parentPath);
177        out.writeObject(name);
178        int nbProperties = (properties == null ? 0 : properties.size());
179        out.writeInt(nbProperties);
180        if (properties != null) {
181            for (Map.Entry<String, Serializable> entry : properties.entrySet()) {
182                out.writeObject(entry.getKey());
183                out.writeObject(entry.getValue());
184            }
185        }
186        if (blob != null) {
187            out.writeBoolean(true);
188            out.writeObject(blob);
189        } else {
190            out.writeBoolean(false);
191        }
192        if (blobInfo != null) {
193            out.writeBoolean(true);
194            out.writeObject(blobInfo.key);
195            out.writeObject(blobInfo.digest);
196            out.writeLong(blobInfo.length);
197            out.writeObject(blobInfo.filename);
198            out.writeObject(blobInfo.encoding);
199            out.writeObject(blobInfo.mimeType);
200        } else {
201            out.writeBoolean(false);
202        }
203    }
204
205    @Override
206    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
207        type = (String) in.readObject();
208        parentPath = (String) in.readObject();
209        name = (String) in.readObject();
210        int nbProperties = in.readInt();
211        if (nbProperties > 0) {
212            properties = new HashMap<>(nbProperties);
213            while (nbProperties > 0) {
214                String key = (String) in.readObject();
215                Serializable value = (Serializable) in.readObject();
216                properties.put(key, value);
217                nbProperties--;
218            }
219        }
220        if (in.readBoolean()) {
221            blob = (Blob) in.readObject();
222        }
223        if (in.readBoolean()) {
224            blobInfo = new BlobInfo();
225            blobInfo.key = (String) in.readObject();
226            blobInfo.digest = (String) in.readObject();
227            blobInfo.length = in.readLong();
228            blobInfo.filename = (String) in.readObject();
229            blobInfo.encoding = (String) in.readObject();
230            blobInfo.mimeType = (String) in.readObject();
231        }
232
233    }
234
235    @Override
236    public String toString() {
237        String bi = "";
238        if (blobInfo != null) {
239            bi = String.format("blobInfo(key=%s filename=%s)", blobInfo.key, blobInfo.filename);
240        } else if (blob != null) {
241            bi = String.format("blob(filename=%s)", blob.getFilename());
242        }
243        return String.format("DocumentMessage(type=%s name=%s parentPath=%s bi=%s)", type, name, parentPath, bi);
244    }
245    // TODO: impl hashCode, equals, toString
246}