001
014
015 package com.liferay.portlet.dynamicdatamapping.storage;
016
017 import com.liferay.portal.kernel.util.ArrayUtil;
018 import com.liferay.portal.kernel.util.HtmlUtil;
019 import com.liferay.portal.kernel.util.OrderByComparator;
020 import com.liferay.portal.kernel.util.StringBundler;
021 import com.liferay.portal.kernel.util.StringPool;
022 import com.liferay.portal.kernel.xml.Document;
023 import com.liferay.portal.kernel.xml.Element;
024 import com.liferay.portal.kernel.xml.Node;
025 import com.liferay.portal.kernel.xml.SAXReaderUtil;
026 import com.liferay.portal.kernel.xml.XPath;
027 import com.liferay.portal.service.ServiceContext;
028 import com.liferay.portal.util.PortalUtil;
029 import com.liferay.portlet.dynamicdatamapping.model.DDMContent;
030 import com.liferay.portlet.dynamicdatamapping.model.DDMStorageLink;
031 import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
032 import com.liferay.portlet.dynamicdatamapping.service.DDMContentLocalServiceUtil;
033 import com.liferay.portlet.dynamicdatamapping.service.DDMStorageLinkLocalServiceUtil;
034 import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
035 import com.liferay.portlet.dynamicdatamapping.storage.query.ComparisonOperator;
036 import com.liferay.portlet.dynamicdatamapping.storage.query.Condition;
037 import com.liferay.portlet.dynamicdatamapping.storage.query.FieldCondition;
038 import com.liferay.portlet.dynamicdatamapping.storage.query.FieldConditionImpl;
039 import com.liferay.portlet.dynamicdatamapping.storage.query.Junction;
040 import com.liferay.portlet.dynamicdatamapping.storage.query.LogicalOperator;
041
042 import java.io.Serializable;
043
044 import java.util.ArrayList;
045 import java.util.Collections;
046 import java.util.Date;
047 import java.util.HashMap;
048 import java.util.Iterator;
049 import java.util.List;
050 import java.util.Map;
051
052
056 public class XMLStorageAdapter extends BaseStorageAdapter {
057
058 @Override
059 protected long doCreate(
060 long companyId, long ddmStructureId, Fields fields,
061 ServiceContext serviceContext)
062 throws Exception {
063
064 long classNameId = PortalUtil.getClassNameId(
065 DDMContent.class.getName());
066
067 Document document = SAXReaderUtil.createDocument();
068
069 Element rootElement = document.addElement("root");
070
071 Iterator<Field> itr = fields.iterator();
072
073 while (itr.hasNext()) {
074 Field field = itr.next();
075
076 Object value = field.getValue();
077
078 if (value instanceof Date) {
079 Date valueDate = (Date)value;
080
081 value = valueDate.getTime();
082 }
083
084 String valueString = String.valueOf(value);
085
086 if (valueString != null) {
087 valueString = valueString.trim();
088 }
089
090 _appendField(rootElement, field.getName(), valueString);
091 }
092
093 DDMContent ddmContent = DDMContentLocalServiceUtil.addContent(
094 serviceContext.getUserId(), serviceContext.getScopeGroupId(),
095 DDMStorageLink.class.getName(), null, document.formattedString(),
096 serviceContext);
097
098 DDMStorageLinkLocalServiceUtil.addStorageLink(
099 classNameId, ddmContent.getPrimaryKey(), ddmStructureId,
100 serviceContext);
101
102 return ddmContent.getPrimaryKey();
103 }
104
105 @Override
106 protected void doDeleteByClass(long classPK) throws Exception {
107 DDMContentLocalServiceUtil.deleteDDMContent(classPK);
108
109 DDMStorageLinkLocalServiceUtil.deleteClassStorageLink(classPK);
110 }
111
112 @Override
113 protected void doDeleteByDDMStructure(long ddmStructureId)
114 throws Exception {
115
116 List<DDMStorageLink> ddmStorageLinks =
117 DDMStorageLinkLocalServiceUtil.getStructureStorageLinks(
118 ddmStructureId);
119
120 for (DDMStorageLink ddmStorageLink : ddmStorageLinks) {
121 DDMContentLocalServiceUtil.deleteDDMContent(
122 ddmStorageLink.getClassPK());
123 }
124
125 DDMStorageLinkLocalServiceUtil.deleteStructureStorageLinks(
126 ddmStructureId);
127 }
128
129 @Override
130 protected List<Fields> doGetFieldsListByClasses(
131 long ddmStructureId, long[] classPKs, List<String> fieldNames,
132 OrderByComparator orderByComparator)
133 throws Exception {
134
135 return _doQuery(
136 ddmStructureId, classPKs, fieldNames, null, orderByComparator);
137 }
138
139 @Override
140 protected List<Fields> doGetFieldsListByDDMStructure(
141 long ddmStructureId, List<String> fieldNames,
142 OrderByComparator orderByComparator)
143 throws Exception {
144
145 return _doQuery(ddmStructureId, fieldNames, null, orderByComparator);
146 }
147
148 @Override
149 protected Map<Long, Fields> doGetFieldsMapByClasses(
150 long ddmStructureId, long[] classPKs, List<String> fieldNames)
151 throws Exception {
152
153 return _doQuery(ddmStructureId, classPKs, fieldNames);
154 }
155
156 @Override
157 protected List<Fields> doQuery(
158 long ddmStructureId, List<String> fieldNames, Condition condition,
159 OrderByComparator orderByComparator)
160 throws Exception {
161
162 return _doQuery(
163 ddmStructureId, fieldNames, condition, orderByComparator);
164 }
165
166 @Override
167 protected int doQueryCount(long ddmStructureId, Condition condition)
168 throws Exception {
169
170 XPath conditionXPath = null;
171
172 if (condition != null) {
173 conditionXPath = _parseCondition(condition);
174 }
175
176 int count = 0;
177
178 long[] classPKs = _getStructureClassPKs(ddmStructureId);
179
180 for (long classPK : classPKs) {
181 DDMContent ddmContent = DDMContentLocalServiceUtil.getContent(
182 classPK);
183
184 Document document = SAXReaderUtil.read(ddmContent.getXml());
185
186 if ((conditionXPath == null) ||
187 ((conditionXPath != null) &&
188 conditionXPath.booleanValueOf(document))) {
189
190 count++;
191 }
192 }
193
194 return count;
195 }
196
197 @Override
198 protected void doUpdate(
199 long classPK, Fields fields, boolean mergeFields,
200 ServiceContext serviceContext)
201 throws Exception {
202
203 DDMContent ddmContent = DDMContentLocalServiceUtil.getContent(classPK);
204
205 Document document = null;
206
207 Element rootElement = null;
208
209 if (mergeFields) {
210 document = SAXReaderUtil.read(ddmContent.getXml());
211
212 rootElement = document.getRootElement();
213 }
214 else {
215 document = SAXReaderUtil.createDocument();
216
217 rootElement = document.addElement("root");
218 }
219
220 Iterator<Field> itr = fields.iterator();
221
222 while (itr.hasNext()) {
223 Field field = itr.next();
224
225 Object value = field.getValue();
226
227 if (value instanceof Date) {
228 Date valueDate = (Date)value;
229
230 value = valueDate.getTime();
231 }
232
233 String fieldName = field.getName();
234 String fieldValue = String.valueOf(value);
235
236 Element dynamicElementElement = _getElementByName(
237 document, fieldName);
238
239 if (dynamicElementElement == null) {
240 _appendField(rootElement, fieldName, fieldValue);
241 }
242 else {
243 _updateField(dynamicElementElement, fieldName, fieldValue);
244 }
245 }
246
247 ddmContent.setModifiedDate(serviceContext.getModifiedDate(null));
248 ddmContent.setXml(document.formattedString());
249
250 DDMContentLocalServiceUtil.updateContent(
251 ddmContent.getPrimaryKey(), ddmContent.getName(),
252 ddmContent.getDescription(), ddmContent.getXml(), serviceContext);
253 }
254
255 private Element _appendField(
256 Element rootElement, String fieldName, String fieldValue) {
257
258 Element dynamicElementElement = rootElement.addElement(
259 "dynamic-element");
260
261 dynamicElementElement.addElement("dynamic-content");
262
263 _updateField(dynamicElementElement, fieldName, fieldValue);
264
265 return dynamicElementElement;
266 }
267
268 private List<Fields> _doQuery(
269 long ddmStructureId, List<String> fieldNames, Condition condition,
270 OrderByComparator orderByComparator)
271 throws Exception {
272
273 return _doQuery(
274 ddmStructureId, _getStructureClassPKs(ddmStructureId), fieldNames,
275 condition, orderByComparator);
276 }
277
278 private Map<Long, Fields> _doQuery(
279 long ddmStructureId, long[] classPKs, List<String> fieldNames)
280 throws Exception {
281
282 Map<Long, Fields> fieldsMap = new HashMap<Long, Fields>();
283
284 List<Fields> fieldsList = _doQuery(
285 ddmStructureId, classPKs, fieldNames, null, null);
286
287 for (int i = 0; i < fieldsList.size(); i++) {
288 Fields fields = fieldsList.get(i);
289
290 fieldsMap.put(classPKs[i], fields);
291 }
292
293 return fieldsMap;
294 }
295
296 private List<Fields> _doQuery(
297 long ddmStructureId, long[] classPKs, List<String> fieldNames,
298 Condition condition, OrderByComparator orderByComparator)
299 throws Exception {
300
301 List<Fields> fieldsList = new ArrayList<Fields>();
302
303 XPath conditionXPath = null;
304
305 if (condition != null) {
306 conditionXPath = _parseCondition(condition);
307 }
308
309 DDMStructure ddmStructure =
310 DDMStructureLocalServiceUtil.getDDMStructure(ddmStructureId);
311
312 for (long classPK : classPKs) {
313 DDMContent ddmContent = DDMContentLocalServiceUtil.getContent(
314 classPK);
315
316 Document document = SAXReaderUtil.read(ddmContent.getXml());
317
318 if ((conditionXPath != null) &&
319 !conditionXPath.booleanValueOf(document)) {
320
321 continue;
322 }
323
324 Fields fields = new Fields();
325
326 Element rootElement = document.getRootElement();
327
328 List<Element> dynamicElementElements = rootElement.elements(
329 "dynamic-element");
330
331 for (Element dynamicElementElement : dynamicElementElements) {
332 String fieldName = dynamicElementElement.attributeValue("name");
333 String fieldValue = dynamicElementElement.elementText(
334 "dynamic-content");
335
336 if (!ddmStructure.hasField(fieldName) ||
337 ((fieldNames != null) && !fieldNames.contains(fieldName))) {
338
339 continue;
340 }
341
342 String fieldDataType = ddmStructure.getFieldDataType(fieldName);
343
344 Serializable fieldValueSerializable =
345 FieldConstants.getSerializable(fieldDataType, fieldValue);
346
347 Field field = new Field(
348 ddmStructureId, fieldName, fieldValueSerializable);
349
350 fields.put(field);
351 }
352
353 fieldsList.add(fields);
354 }
355
356 if (orderByComparator != null) {
357 Collections.sort(fieldsList, orderByComparator);
358 }
359
360 return fieldsList;
361 }
362
363 private Element _getElementByName(Document document, String name) {
364 name = HtmlUtil.escapeXPathAttribute(name);
365
366 XPath xPathSelector = SAXReaderUtil.createXPath(
367 "
368
369 List<Node> nodes = xPathSelector.selectNodes(document);
370
371 if (nodes.size() == 1) {
372 return (Element)nodes.get(0);
373 }
374 else {
375 return null;
376 }
377 }
378
379 private long[] _getStructureClassPKs(long ddmStructureId) throws Exception {
380 List<Long> classPKs = new ArrayList<Long>();
381
382 List<DDMStorageLink> ddmStorageLinks =
383 DDMStorageLinkLocalServiceUtil.getStructureStorageLinks(
384 ddmStructureId);
385
386 for (DDMStorageLink ddmStorageLink : ddmStorageLinks) {
387 classPKs.add(ddmStorageLink.getClassPK());
388 }
389
390 return ArrayUtil.toArray(classPKs.toArray(new Long[classPKs.size()]));
391 }
392
393 private XPath _parseCondition(Condition condition) {
394 StringBundler sb = new StringBundler(4);
395
396 sb.append("
397 sb.append(StringPool.OPEN_BRACKET);
398 sb.append(_toXPath(condition));
399 sb.append(StringPool.CLOSE_BRACKET);
400
401 return SAXReaderUtil.createXPath(sb.toString());
402 }
403
404 private String _toXPath(Condition condition) {
405 StringBundler sb = new StringBundler();
406
407 if (condition.isJunction()) {
408 sb.append(StringPool.OPEN_PARENTHESIS);
409 sb.append(_toXPath((Junction)condition));
410 sb.append(StringPool.CLOSE_PARENTHESIS);
411 }
412 else {
413 sb.append(_toXPath((FieldConditionImpl)condition));
414 }
415
416 return sb.toString();
417 }
418
419 private String _toXPath(FieldCondition fieldCondition) {
420 StringBundler sb = new StringBundler(6);
421
422 sb.append("(@name=");
423
424 String name = HtmlUtil.escapeXPathAttribute(
425 String.valueOf(fieldCondition.getName()));
426
427 sb.append(name);
428
429 ComparisonOperator comparisonOperator =
430 fieldCondition.getComparisonOperator();
431
432 if (comparisonOperator.equals(ComparisonOperator.LIKE)) {
433 sb.append(" and matches(dynamic-content, ");
434 }
435 else {
436 sb.append(" and dynamic-content= ");
437 }
438
439 String value = HtmlUtil.escapeXPathAttribute(
440 String.valueOf(fieldCondition.getValue()));
441
442 sb.append(value);
443
444 if (comparisonOperator.equals(ComparisonOperator.LIKE)) {
445 sb.append(StringPool.CLOSE_PARENTHESIS);
446 }
447
448 sb.append(StringPool.CLOSE_PARENTHESIS);
449
450 return sb.toString();
451 }
452
453 private String _toXPath(Junction junction) {
454 StringBundler sb = new StringBundler();
455
456 LogicalOperator logicalOperator = junction.getLogicalOperator();
457
458 String logicalOperatorString = logicalOperator.toString();
459
460 Iterator<Condition> itr = junction.iterator();
461
462 while (itr.hasNext()) {
463 Condition condition = itr.next();
464
465 sb.append(_toXPath(condition));
466
467 if (itr.hasNext()) {
468 sb.append(StringPool.SPACE);
469 sb.append(logicalOperatorString.toLowerCase());
470 sb.append(StringPool.SPACE);
471 }
472 }
473
474 return sb.toString();
475 }
476
477 private void _updateField(
478 Element dynamicElementElement, String fieldName, String value) {
479
480 Element dynamicContentElement = dynamicElementElement.element(
481 "dynamic-content");
482
483 dynamicElementElement.addAttribute("name", fieldName);
484
485 dynamicContentElement.clearContent();
486
487 dynamicContentElement.addCDATA(value);
488 }
489
490 }