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