1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.ui.form.field.transformer.item;
35
36 import info.magnolia.cms.beans.runtime.FileProperties;
37 import info.magnolia.cms.core.Path;
38 import info.magnolia.jcr.util.NodeTypes;
39 import info.magnolia.jcr.util.NodeUtil;
40 import info.magnolia.objectfactory.Components;
41 import info.magnolia.ui.form.field.definition.BasicUploadFieldDefinition;
42 import info.magnolia.ui.form.field.transformer.Transformer;
43 import info.magnolia.ui.form.field.upload.UploadReceiver;
44 import info.magnolia.ui.vaadin.integration.jcr.AbstractJcrNodeAdapter;
45 import info.magnolia.ui.vaadin.integration.jcr.DefaultProperty;
46 import info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeAdapter;
47 import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter;
48
49 import java.io.FileInputStream;
50 import java.io.InputStream;
51 import java.io.OutputStream;
52 import java.util.ArrayList;
53 import java.util.Date;
54 import java.util.List;
55 import java.util.Locale;
56
57 import javax.inject.Inject;
58 import javax.jcr.Binary;
59 import javax.jcr.Node;
60 import javax.jcr.RepositoryException;
61
62 import org.apache.commons.io.IOUtils;
63 import org.apache.jackrabbit.JcrConstants;
64 import org.apache.jackrabbit.value.BinaryImpl;
65 import org.apache.jackrabbit.value.ValueFactoryImpl;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69 import com.vaadin.data.Item;
70 import com.vaadin.data.Property;
71
72
73
74
75
76
77 public class FileTransformer<T extends UploadReceiver> implements Transformer<T> {
78
79 private static final Logger log = LoggerFactory.getLogger(FileTransformer.class);
80
81 protected Item relatedFormItem;
82 protected final BasicUploadFieldDefinition definition;
83 protected final Class<T> type;
84 private Locale locale;
85
86 protected String basePropertyName;
87
88 protected String i18NPropertyName;
89
90 private boolean isReadOnly = false;
91
92 @Inject
93 public FileTransformer(Item relatedFormItem, BasicUploadFieldDefinition definition, Class<T> type) {
94 this.definition = definition;
95 this.relatedFormItem = relatedFormItem;
96 this.type = type;
97 this.basePropertyName = getBasePropertyName();
98 if (hasI18NSupport()) {
99 this.i18NPropertyName = this.basePropertyName;
100 }
101 }
102
103
104
105
106
107
108 @Override
109 public void writeToItem(T newValue) {
110 Item item = getOrCreateFileItem();
111 if (isValid(newValue, item)) {
112 populateItem(newValue, item);
113 getRootItem().addChild((AbstractJcrNodeAdapter) item);
114 } else {
115 handleInvalid(newValue, item);
116 }
117 }
118
119
120
121
122 @Override
123 public T readFromItem() {
124
125 JcrNodeAdapter rootItem = getRootItem();
126
127 if (!rootItem.hasChildItemChanges()) {
128 populateStoredChildItems(rootItem);
129 }
130
131 Item item = getOrCreateFileItem();
132 return createPropertyFromItem(item);
133 }
134
135
136
137
138 protected Item getOrCreateFileItem() {
139 String itemName = getItemName();
140 Item child = getRootItem().getChild(itemName);
141 if (child != null) {
142 return child;
143 }
144 Node node = null;
145 try {
146 node = getRootItem().getJcrItem();
147 if (node.hasNode(itemName) && !(getRootItem() instanceof JcrNewNodeAdapter)) {
148 child = new JcrNodeAdapter(node.getNode(itemName));
149 } else {
150 child = new JcrNewNodeAdapter(node, NodeTypes.Resource.NAME, itemName);
151 }
152 } catch (RepositoryException e) {
153 log.error("Could get or create a child Item for {} ", NodeUtil.getPathIfPossible(node), e);
154 }
155 return child;
156 }
157
158
159
160
161 protected String getItemName() {
162 if (hasI18NSupport()) {
163 return this.i18NPropertyName;
164 }
165 return this.basePropertyName;
166 }
167
168
169
170
171 public T createPropertyFromItem(Item item) {
172 T uploadReceiver = initializeUploadReceiver();
173
174
175 if (item.getItemProperty(JcrConstants.JCR_DATA) != null && item.getItemProperty(JcrConstants.JCR_DATA).getValue() != null) {
176 String fileName = item.getItemProperty(FileProperties.PROPERTY_FILENAME) != null ? (String) item.getItemProperty(FileProperties.PROPERTY_FILENAME).getValue() : "";
177 String MIMEType = item.getItemProperty(FileProperties.PROPERTY_CONTENTTYPE) != null ? String.valueOf(item.getItemProperty(FileProperties.PROPERTY_CONTENTTYPE).getValue()) : "";
178
179 try (OutputStream out = uploadReceiver.receiveUpload(fileName, MIMEType);
180 InputStream in = ((BinaryImpl) item.getItemProperty(JcrConstants.JCR_DATA).getValue()).getStream()) {
181 IOUtils.copy(in, out);
182 } catch (Exception e) {
183 e.printStackTrace();
184 }
185 }
186 return uploadReceiver;
187 }
188
189 protected T initializeUploadReceiver() {
190 return (T) Components.newInstance(UploadReceiver.class, Path.getTempDirectory());
191 }
192
193
194
195
196 protected boolean isValid(T newValue, Item item) {
197 return newValue != null && !newValue.isEmpty();
198 }
199
200
201
202
203
204
205 public Item populateItem(T newValue, Item item) {
206
207 Property<Binary> data = getOrCreateProperty(item, JcrConstants.JCR_DATA, Binary.class);
208 if (newValue != null) {
209 try {
210 data.setValue(ValueFactoryImpl.getInstance().createBinary(new FileInputStream(newValue.getFile())));
211 } catch (Exception re) {
212 log.error("Could not get Binary. Upload will not be performed", re);
213 getRootItem().removeChild((AbstractJcrNodeAdapter) item);
214 return null;
215 }
216 }
217 getOrCreateProperty(item, FileProperties.PROPERTY_FILENAME, String.class).setValue(newValue.getFileName());
218 getOrCreateProperty(item, FileProperties.PROPERTY_CONTENTTYPE, String.class).setValue(newValue.getMimeType());
219 getOrCreateProperty(item, FileProperties.PROPERTY_LASTMODIFIED, Date.class).setValue(new Date());
220 getOrCreateProperty(item, FileProperties.PROPERTY_SIZE, Long.class).setValue(newValue.getFileSize());
221 getOrCreateProperty(item, FileProperties.PROPERTY_EXTENSION, String.class).setValue(newValue.getExtension());
222 return item;
223 }
224
225
226
227
228
229
230 protected void handleInvalid(T newValue, Item item) {
231 if (((AbstractJcrNodeAdapter) item).getParent() != null) {
232 ((AbstractJcrNodeAdapter) item).getParent().removeChild((AbstractJcrNodeAdapter) item);
233 }
234 }
235
236
237
238
239 protected Property getOrCreateProperty(Item item, String propertyName, Class<?> type) {
240 if (item.getItemProperty(propertyName) == null) {
241 item.addItemProperty(propertyName, new DefaultProperty(type, null));
242 }
243 return item.getItemProperty(propertyName);
244 }
245
246
247
248
249 protected JcrNodeAdapter getRootItem() {
250 return (JcrNodeAdapter) relatedFormItem;
251 }
252
253
254
255
256 protected void populateStoredChildItems(JcrNodeAdapter rootItem) {
257 List<Node> childNodes = getStoredChildNodes(rootItem);
258 for (Node child : childNodes) {
259 JcrNodeAdapter item = new JcrNodeAdapter(child);
260 item.setParent(rootItem);
261 item.getParent().addChild(item);
262 }
263 }
264
265
266
267
268 protected List<Node> getStoredChildNodes(JcrNodeAdapter parent) {
269 try {
270 if (!(parent instanceof JcrNewNodeAdapter) && parent.getJcrItem().hasNodes()) {
271 return NodeUtil.asList(NodeUtil.getNodes(parent.getJcrItem(), NodeUtil.MAGNOLIA_FILTER));
272 }
273 } catch (RepositoryException re) {
274 log.warn("Not able to access the Child Nodes of the following Node Identifier {}", parent.getItemId(), re);
275 }
276 return new ArrayList<Node>();
277 }
278
279 @Override
280 public String getBasePropertyName() {
281 return this.definition.getBinaryNodeName();
282 }
283
284 @Override
285 public Class<T> getType() {
286 return this.type;
287 }
288
289 @Override
290 public boolean isReadOnly() {
291 if (this.isReadOnly) {
292 return true;
293 }
294 final Property property = relatedFormItem.getItemProperty(JcrConstants.JCR_DATA);
295 boolean isPropertyReadOnly = property != null && property.isReadOnly();
296 return isPropertyReadOnly || definition.isReadOnly();
297 }
298
299 @Override
300 public void setReadOnly(boolean isReadOnly) {
301 this.isReadOnly = isReadOnly;
302 }
303
304
305
306
307 @Override
308 public boolean hasI18NSupport() {
309 return definition.isI18n();
310 }
311
312 @Override
313 public void setLocale(Locale locale) {
314 this.locale = locale;
315 }
316
317 @Override
318 public void setI18NPropertyName(String i18nPropertyName) {
319 this.i18NPropertyName = i18nPropertyName;
320 }
321
322 @Override
323 public Locale getLocale() {
324 return this.locale;
325 }
326
327 }