001
014
015 package com.liferay.portlet.dynamicdatamapping.storage;
016
017 import com.liferay.counter.service.CounterLocalServiceUtil;
018 import com.liferay.portal.kernel.exception.PortalException;
019 import com.liferay.portal.kernel.exception.SystemException;
020 import com.liferay.portal.kernel.log.Log;
021 import com.liferay.portal.kernel.log.LogFactoryUtil;
022 import com.liferay.portal.kernel.util.ArrayUtil;
023 import com.liferay.portal.kernel.util.OrderByComparator;
024 import com.liferay.portal.kernel.util.StringBundler;
025 import com.liferay.portal.kernel.util.StringPool;
026 import com.liferay.portal.kernel.util.StringUtil;
027 import com.liferay.portal.kernel.util.Validator;
028 import com.liferay.portal.service.ServiceContext;
029 import com.liferay.portal.util.PortalUtil;
030 import com.liferay.portlet.dynamicdatamapping.model.DDMStorageLink;
031 import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
032 import com.liferay.portlet.dynamicdatamapping.service.DDMStorageLinkLocalServiceUtil;
033 import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
034 import com.liferay.portlet.dynamicdatamapping.storage.query.ComparisonOperator;
035 import com.liferay.portlet.dynamicdatamapping.storage.query.Condition;
036 import com.liferay.portlet.dynamicdatamapping.storage.query.FieldCondition;
037 import com.liferay.portlet.dynamicdatamapping.storage.query.Junction;
038 import com.liferay.portlet.dynamicdatamapping.storage.query.LogicalOperator;
039 import com.liferay.portlet.dynamicdatamapping.util.DDMUtil;
040 import com.liferay.portlet.expando.NoSuchTableException;
041 import com.liferay.portlet.expando.model.ExpandoColumn;
042 import com.liferay.portlet.expando.model.ExpandoColumnConstants;
043 import com.liferay.portlet.expando.model.ExpandoRow;
044 import com.liferay.portlet.expando.model.ExpandoTable;
045 import com.liferay.portlet.expando.model.ExpandoValue;
046 import com.liferay.portlet.expando.service.ExpandoColumnLocalServiceUtil;
047 import com.liferay.portlet.expando.service.ExpandoRowLocalServiceUtil;
048 import com.liferay.portlet.expando.service.ExpandoTableLocalServiceUtil;
049 import com.liferay.portlet.expando.service.ExpandoValueLocalServiceUtil;
050
051 import java.io.Serializable;
052
053 import java.util.ArrayList;
054 import java.util.Collections;
055 import java.util.HashMap;
056 import java.util.Iterator;
057 import java.util.List;
058 import java.util.Locale;
059 import java.util.Map;
060
061 import org.springframework.expression.EvaluationException;
062 import org.springframework.expression.Expression;
063 import org.springframework.expression.ExpressionParser;
064 import org.springframework.expression.ParseException;
065 import org.springframework.expression.spel.standard.SpelExpressionParser;
066 import org.springframework.expression.spel.support.StandardEvaluationContext;
067
068
073 public class ExpandoStorageAdapter extends BaseStorageAdapter {
074
075 @Override
076 protected long doCreate(
077 long companyId, long ddmStructureId, Fields fields,
078 ServiceContext serviceContext)
079 throws Exception {
080
081 ExpandoTable expandoTable = _getExpandoTable(
082 companyId, ddmStructureId, fields);
083
084 ExpandoRow expandoRow = ExpandoRowLocalServiceUtil.addRow(
085 expandoTable.getTableId(), CounterLocalServiceUtil.increment());
086
087 _updateFields(expandoTable, expandoRow.getClassPK(), fields);
088
089 DDMStorageLinkLocalServiceUtil.addStorageLink(
090 expandoTable.getClassNameId(), expandoRow.getRowId(),
091 ddmStructureId, serviceContext);
092
093 return expandoRow.getRowId();
094 }
095
096 @Override
097 protected void doDeleteByClass(long classPK) throws Exception {
098 ExpandoRowLocalServiceUtil.deleteRow(classPK);
099
100 DDMStorageLinkLocalServiceUtil.deleteClassStorageLink(classPK);
101 }
102
103 @Override
104 protected void doDeleteByDDMStructure(long ddmStructureId)
105 throws Exception {
106
107 List<DDMStorageLink> ddmStorageLinks =
108 DDMStorageLinkLocalServiceUtil.getStructureStorageLinks(
109 ddmStructureId);
110
111 for (DDMStorageLink ddmStorageLink : ddmStorageLinks) {
112 ExpandoRowLocalServiceUtil.deleteRow(ddmStorageLink.getClassPK());
113 }
114
115 DDMStorageLinkLocalServiceUtil.deleteStructureStorageLinks(
116 ddmStructureId);
117 }
118
119 @Override
120 protected List<Fields> doGetFieldsListByClasses(
121 long ddmStructureId, long[] classPKs, List<String> fieldNames,
122 OrderByComparator orderByComparator)
123 throws Exception {
124
125 return _doQuery(
126 ddmStructureId, classPKs, fieldNames, null, orderByComparator);
127 }
128
129 @Override
130 protected List<Fields> doGetFieldsListByDDMStructure(
131 long ddmStructureId, List<String> fieldNames,
132 OrderByComparator orderByComparator)
133 throws Exception {
134
135 return _doQuery(ddmStructureId, fieldNames, null, orderByComparator);
136 }
137
138 @Override
139 protected Map<Long, Fields> doGetFieldsMapByClasses(
140 long ddmStructureId, long[] classPKs, List<String> fieldNames)
141 throws Exception {
142
143 return _doQuery(ddmStructureId, classPKs, fieldNames);
144 }
145
146 @Override
147 protected List<Fields> doQuery(
148 long ddmStructureId, List<String> fieldNames, Condition condition,
149 OrderByComparator orderByComparator)
150 throws Exception {
151
152 return _doQuery(
153 ddmStructureId, fieldNames, condition, orderByComparator);
154 }
155
156 @Override
157 protected int doQueryCount(long ddmStructureId, Condition condition)
158 throws Exception {
159
160 Expression expression = null;
161
162 if (condition != null) {
163 expression = _parseExpression(condition);
164 }
165
166 int count = 0;
167
168 long[] expandoRowIds = _getExpandoRowIds(ddmStructureId);
169
170 for (long expandoRowId : expandoRowIds) {
171 List<ExpandoValue> expandoValues =
172 ExpandoValueLocalServiceUtil.getRowValues(expandoRowId);
173
174 if ((expression == null) ||
175 ((expression != null) &&
176 _booleanValueOf(expression, expandoValues))) {
177
178 count++;
179 }
180 }
181
182 return count;
183 }
184
185 @Override
186 protected void doUpdate(
187 long classPK, Fields fields, boolean mergeFields,
188 ServiceContext serviceContext)
189 throws Exception {
190
191 ExpandoRow expandoRow = ExpandoRowLocalServiceUtil.getRow(classPK);
192
193 DDMStorageLink ddmStorageLink =
194 DDMStorageLinkLocalServiceUtil.getClassStorageLink(
195 expandoRow.getRowId());
196
197 ExpandoTable expandoTable = _getExpandoTable(
198 expandoRow.getCompanyId(), ddmStorageLink.getStructureId(), fields);
199
200 if (mergeFields) {
201 fields = DDMUtil.mergeFields(fields, getFields(classPK));
202 }
203
204 ExpandoValueLocalServiceUtil.deleteRowValues(expandoRow.getRowId());
205
206 _updateFields(expandoTable, expandoRow.getClassPK(), fields);
207 }
208
209 private boolean _booleanValueOf(
210 Expression expression, List<ExpandoValue> expandoValues) {
211
212 try {
213 StandardEvaluationContext standardEvaluationContext =
214 new StandardEvaluationContext();
215
216 standardEvaluationContext.setBeanResolver(
217 new ExpandoValueBeanResolver(expandoValues));
218
219 return expression.getValue(
220 standardEvaluationContext, Boolean.class);
221 }
222 catch (EvaluationException ee) {
223 _log.error("Unable to evaluate expression", ee);
224 }
225
226 return false;
227 }
228
229 private void _checkExpandoColumns(
230 long ddmStructureId, ExpandoTable expandoTable, Fields fields)
231 throws PortalException, SystemException {
232
233 for (String name : fields.getNames()) {
234 ExpandoColumn expandoColumn =
235 ExpandoColumnLocalServiceUtil.getColumn(
236 expandoTable.getTableId(), name);
237
238 if (expandoColumn != null) {
239 continue;
240 }
241
242 int type = ExpandoColumnConstants.STRING_LOCALIZED;
243
244 Field field = fields.get(name);
245
246 if (field.isRepeatable()) {
247 type = ExpandoColumnConstants.STRING_ARRAY_LOCALIZED;
248 }
249
250 ExpandoColumnLocalServiceUtil.addColumn(
251 expandoTable.getTableId(), name, type);
252 }
253 }
254
255 private List<Fields> _doQuery(
256 long ddmStructureId, List<String> fieldNames, Condition condition,
257 OrderByComparator orderByComparator)
258 throws Exception {
259
260 return _doQuery(
261 ddmStructureId, _getExpandoRowIds(ddmStructureId), fieldNames,
262 condition, orderByComparator);
263 }
264
265 private Map<Long, Fields> _doQuery(
266 long ddmStructureId, long[] classPKs, List<String> fieldNames)
267 throws Exception {
268
269 Map<Long, Fields> fieldsMap = new HashMap<Long, Fields>();
270
271 List<Fields> fieldsList = _doQuery(
272 ddmStructureId, classPKs, fieldNames, null, null);
273
274 for (int i = 0; i < fieldsList.size(); i++) {
275 Fields fields = fieldsList.get(i);
276
277 fieldsMap.put(classPKs[i], fields);
278 }
279
280 return fieldsMap;
281 }
282
283 private List<Fields> _doQuery(
284 long ddmStructureId, long[] expandoRowIds, List<String> fieldNames,
285 Condition condition, OrderByComparator orderByComparator)
286 throws Exception {
287
288 List<Fields> fieldsList = new ArrayList<Fields>();
289
290 Expression expression = null;
291
292 if (condition != null) {
293 expression = _parseExpression(condition);
294 }
295
296 DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(
297 ddmStructureId);
298
299 for (long expandoRowId : expandoRowIds) {
300 List<ExpandoValue> expandoValues =
301 ExpandoValueLocalServiceUtil.getRowValues(expandoRowId);
302
303 if ((expression == null) ||
304 ((expression != null) &&
305 _booleanValueOf(expression, expandoValues))) {
306
307 Fields fields = new Fields();
308
309 for (ExpandoValue expandoValue : expandoValues) {
310 ExpandoColumn column = expandoValue.getColumn();
311
312 String fieldName = column.getName();
313
314 if (ddmStructure.hasField(fieldName) &&
315 ((fieldNames == null) ||
316 ((fieldNames != null) &&
317 fieldNames.contains(fieldName)))) {
318
319 Field field = new Field();
320
321 field.setDefaultLocale(expandoValue.getDefaultLocale());
322 field.setDDMStructureId(ddmStructureId);
323 field.setName(fieldName);
324
325 String fieldType = ddmStructure.getFieldType(fieldName);
326
327 Map<Locale, List<Serializable>> valuesMap =
328 _getValuesMap(
329 column.getType(), fieldType,
330 expandoValue.getSerializable());
331
332 field.setValuesMap(valuesMap);
333
334 fields.put(field);
335 }
336 }
337
338 fieldsList.add(fields);
339 }
340 }
341
342 if (orderByComparator != null) {
343 Collections.sort(fieldsList, orderByComparator);
344 }
345
346 return fieldsList;
347 }
348
349 private long[] _getExpandoRowIds(long ddmStructureId)
350 throws SystemException {
351
352 List<Long> expandoRowIds = new ArrayList<Long>();
353
354 List<DDMStorageLink> ddmStorageLinks =
355 DDMStorageLinkLocalServiceUtil.getStructureStorageLinks(
356 ddmStructureId);
357
358 for (DDMStorageLink ddmStorageLink : ddmStorageLinks) {
359 expandoRowIds.add(ddmStorageLink.getClassPK());
360 }
361
362 return ArrayUtil.toArray(
363 expandoRowIds.toArray(new Long[expandoRowIds.size()]));
364 }
365
366 private ExpandoTable _getExpandoTable(
367 long companyId, long ddmStructureId, Fields fields)
368 throws PortalException, SystemException {
369
370 ExpandoTable expandoTable = null;
371
372 long classNameId = PortalUtil.getClassNameId(
373 ExpandoStorageAdapter.class.getName());
374
375 try {
376 expandoTable = ExpandoTableLocalServiceUtil.getTable(
377 companyId, classNameId, String.valueOf(ddmStructureId));
378 }
379 catch (NoSuchTableException nste) {
380 expandoTable = ExpandoTableLocalServiceUtil.addTable(
381 companyId, classNameId, String.valueOf(ddmStructureId));
382 }
383
384 _checkExpandoColumns(ddmStructureId, expandoTable, fields);
385
386 return expandoTable;
387 }
388
389 private Map<Locale, List<Serializable>> _getValuesMap(
390 int columnType, String fieldType, Serializable data) {
391
392 Map<Locale, List<Serializable>> valuesMap =
393 new HashMap<Locale, List<Serializable>>();
394
395 if (columnType == ExpandoColumnConstants.STRING_ARRAY_LOCALIZED) {
396 Map<Locale, String[]> stringArrayMap = (Map<Locale, String[]>)data;
397
398 for (Locale locale : stringArrayMap.keySet()) {
399 String[] value = stringArrayMap.get(locale);
400
401 if (Validator.isNull(value)) {
402 continue;
403 }
404
405 valuesMap.put(locale, _transformValue(fieldType, value));
406 }
407 }
408 else {
409 Map<Locale, String> stringMap = (Map<Locale, String>)data;
410
411 for (Locale locale : stringMap.keySet()) {
412 String value = stringMap.get(locale);
413
414 if (Validator.isNull(value)) {
415 continue;
416 }
417
418 valuesMap.put(locale, _transformValue(fieldType, value));
419 }
420 }
421
422 return valuesMap;
423 }
424
425 private Expression _parseExpression(Condition condition) {
426 String expression = _toExpression(condition);
427
428 try {
429 ExpressionParser expressionParser = new SpelExpressionParser();
430
431 return expressionParser.parseExpression(expression);
432 }
433 catch (ParseException pe) {
434 _log.error("Unable to parse expression " + expression, pe);
435 }
436
437 return null;
438 }
439
440 private String _toExpression(Condition condition) {
441 if (condition.isJunction()) {
442 Junction junction = (Junction)condition;
443
444 return StringPool.OPEN_PARENTHESIS.concat(
445 _toExpression(junction)).concat(StringPool.CLOSE_PARENTHESIS);
446 }
447 else {
448 FieldCondition fieldCondition = (FieldCondition)condition;
449
450 return _toExpression(fieldCondition);
451 }
452 }
453
454 private String _toExpression(FieldCondition fieldCondition) {
455 StringBundler sb = new StringBundler(5);
456
457 sb.append("(@");
458 sb.append(fieldCondition.getName());
459
460 ComparisonOperator comparisonOperator =
461 fieldCondition.getComparisonOperator();
462
463 if (comparisonOperator.equals(ComparisonOperator.LIKE)) {
464 sb.append(".data matches ");
465 }
466 else {
467 sb.append(".data == ");
468 }
469
470 String value = StringUtil.quote(
471 String.valueOf(fieldCondition.getValue()));
472
473 sb.append(value);
474 sb.append(StringPool.CLOSE_PARENTHESIS);
475
476 return sb.toString();
477 }
478
479 private String _toExpression(Junction junction) {
480 StringBundler sb = new StringBundler();
481
482 LogicalOperator logicalOperator = junction.getLogicalOperator();
483
484 Iterator<Condition> itr = junction.iterator();
485
486 while (itr.hasNext()) {
487 Condition condition = itr.next();
488
489 sb.append(_toExpression(condition));
490
491 if (itr.hasNext()) {
492 sb.append(StringPool.SPACE);
493 sb.append(logicalOperator.toString());
494 sb.append(StringPool.SPACE);
495 }
496 }
497
498 return sb.toString();
499 }
500
501 private List<Serializable> _transformValue(String type, String value) {
502 List<Serializable> serializables = new ArrayList<Serializable>();
503
504 Serializable serializable = FieldConstants.getSerializable(type, value);
505
506 serializables.add(serializable);
507
508 return serializables;
509 }
510
511 private List<Serializable> _transformValue(String type, String[] values) {
512 List<Serializable> serializables = new ArrayList<Serializable>();
513
514 for (String value : values) {
515 Serializable serializable = FieldConstants.getSerializable(
516 type, value);
517
518 serializables.add(serializable);
519 }
520
521 return serializables;
522 }
523
524 private void _updateFields(
525 ExpandoTable expandoTable, long classPK, Fields fields)
526 throws PortalException, SystemException {
527
528 Iterator<Field> itr = fields.iterator();
529
530 while (itr.hasNext()) {
531 Field field = itr.next();
532
533 Map<Locale, ?> dataMap = null;
534
535 if (field.isRepeatable()) {
536 Map<Locale, String[]> stringArrayMap =
537 new HashMap<Locale, String[]>();
538
539 for (Locale locale : field.getAvailableLocales()) {
540 String[] values = ArrayUtil.toStringArray(
541 (Object[])field.getValue(locale));
542
543 stringArrayMap.put(locale, values);
544 }
545
546 dataMap = stringArrayMap;
547 }
548 else {
549 Map<Locale, String> stringMap = new HashMap<Locale, String>();
550
551 for (Locale locale : field.getAvailableLocales()) {
552 String value = String.valueOf(field.getValue(locale));
553
554 stringMap.put(locale, value);
555 }
556
557 dataMap = stringMap;
558 }
559
560 ExpandoValueLocalServiceUtil.addValue(
561 expandoTable.getCompanyId(),
562 ExpandoStorageAdapter.class.getName(), expandoTable.getName(),
563 field.getName(), classPK, dataMap, field.getDefaultLocale());
564 }
565 }
566
567 private static Log _log = LogFactoryUtil.getLog(
568 ExpandoStorageAdapter.class);
569
570 }