001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
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.service.ServiceContext;
028    import com.liferay.portal.util.PortalUtil;
029    import com.liferay.portlet.dynamicdatamapping.model.DDMStorageLink;
030    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
031    import com.liferay.portlet.dynamicdatamapping.service.DDMStorageLinkLocalServiceUtil;
032    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
033    import com.liferay.portlet.dynamicdatamapping.storage.query.ComparisonOperator;
034    import com.liferay.portlet.dynamicdatamapping.storage.query.Condition;
035    import com.liferay.portlet.dynamicdatamapping.storage.query.FieldCondition;
036    import com.liferay.portlet.dynamicdatamapping.storage.query.Junction;
037    import com.liferay.portlet.dynamicdatamapping.storage.query.LogicalOperator;
038    import com.liferay.portlet.expando.NoSuchTableException;
039    import com.liferay.portlet.expando.model.ExpandoColumn;
040    import com.liferay.portlet.expando.model.ExpandoColumnConstants;
041    import com.liferay.portlet.expando.model.ExpandoRow;
042    import com.liferay.portlet.expando.model.ExpandoTable;
043    import com.liferay.portlet.expando.model.ExpandoValue;
044    import com.liferay.portlet.expando.service.ExpandoColumnLocalServiceUtil;
045    import com.liferay.portlet.expando.service.ExpandoRowLocalServiceUtil;
046    import com.liferay.portlet.expando.service.ExpandoTableLocalServiceUtil;
047    import com.liferay.portlet.expando.service.ExpandoValueLocalServiceUtil;
048    
049    import java.io.Serializable;
050    
051    import java.util.ArrayList;
052    import java.util.Collections;
053    import java.util.HashMap;
054    import java.util.Iterator;
055    import java.util.List;
056    import java.util.Map;
057    
058    import org.springframework.expression.EvaluationException;
059    import org.springframework.expression.Expression;
060    import org.springframework.expression.ExpressionParser;
061    import org.springframework.expression.ParseException;
062    import org.springframework.expression.spel.standard.SpelExpressionParser;
063    import org.springframework.expression.spel.support.StandardEvaluationContext;
064    
065    /**
066     * @author Eduardo Lundgren
067     * @author Brian Wing Shun Chan
068     * @author Marcellus Tavares
069     */
070    public class ExpandoStorageAdapter extends BaseStorageAdapter {
071    
072            @Override
073            protected long doCreate(
074                            long companyId, long ddmStructureId, Fields fields,
075                            ServiceContext serviceContext)
076                    throws Exception {
077    
078                    ExpandoTable expandoTable = _getExpandoTable(
079                            companyId, ddmStructureId, fields);
080    
081                    ExpandoRow expandoRow = ExpandoRowLocalServiceUtil.addRow(
082                            expandoTable.getTableId(), CounterLocalServiceUtil.increment());
083    
084                    _updateFields(expandoTable, expandoRow.getClassPK(), fields);
085    
086                    DDMStorageLinkLocalServiceUtil.addStorageLink(
087                            expandoTable.getClassNameId(), expandoRow.getRowId(),
088                            ddmStructureId, serviceContext);
089    
090                    return expandoRow.getRowId();
091            }
092    
093            @Override
094            protected void doDeleteByClass(long classPK) throws Exception {
095                    ExpandoRowLocalServiceUtil.deleteRow(classPK);
096    
097                    DDMStorageLinkLocalServiceUtil.deleteClassStorageLink(classPK);
098            }
099    
100            @Override
101            protected void doDeleteByDDMStructure(long ddmStructureId)
102                    throws Exception {
103    
104                    List<DDMStorageLink> ddmStorageLinks =
105                            DDMStorageLinkLocalServiceUtil.getStructureStorageLinks(
106                                    ddmStructureId);
107    
108                    for (DDMStorageLink ddmStorageLink : ddmStorageLinks) {
109                            ExpandoRowLocalServiceUtil.deleteRow(ddmStorageLink.getClassPK());
110                    }
111    
112                    DDMStorageLinkLocalServiceUtil.deleteStructureStorageLinks(
113                            ddmStructureId);
114            }
115    
116            @Override
117            protected List<Fields> doGetFieldsListByClasses(
118                            long ddmStructureId, long[] classPKs, List<String> fieldNames,
119                            OrderByComparator orderByComparator)
120                    throws Exception {
121    
122                    return _doQuery(
123                            ddmStructureId, classPKs, fieldNames, null, orderByComparator);
124            }
125    
126            @Override
127            protected List<Fields> doGetFieldsListByDDMStructure(
128                            long ddmStructureId, List<String> fieldNames,
129                            OrderByComparator orderByComparator)
130                    throws Exception {
131    
132                    return _doQuery(ddmStructureId, fieldNames, null, orderByComparator);
133            }
134    
135            @Override
136            protected Map<Long, Fields> doGetFieldsMapByClasses(
137                            long ddmStructureId, long[] classPKs, List<String> fieldNames)
138                    throws Exception {
139    
140                    return _doQuery(ddmStructureId, classPKs, fieldNames);
141            }
142    
143            @Override
144            protected List<Fields> doQuery(
145                            long ddmStructureId, List<String> fieldNames, Condition condition,
146                            OrderByComparator orderByComparator)
147                    throws Exception {
148    
149                    return _doQuery(
150                            ddmStructureId, fieldNames, condition, orderByComparator);
151            }
152    
153            @Override
154            protected int doQueryCount(long ddmStructureId, Condition condition)
155                    throws Exception {
156    
157                    Expression expression = null;
158    
159                    if (condition != null) {
160                            expression = _parseExpression(condition);
161                    }
162    
163                    int count = 0;
164    
165                    long[] expandoRowIds = _getExpandoRowIds(ddmStructureId);
166    
167                    for (long expandoRowId : expandoRowIds) {
168                            List<ExpandoValue> expandoValues =
169                                    ExpandoValueLocalServiceUtil.getRowValues(expandoRowId);
170    
171                            if ((expression == null) ||
172                                    ((expression != null) &&
173                                     _booleanValueOf(expression, expandoValues))) {
174    
175                                    count++;
176                            }
177                    }
178    
179                    return count;
180            }
181    
182            @Override
183            protected void doUpdate(
184                            long classPK, Fields fields, boolean mergeFields,
185                            ServiceContext serviceContext)
186                    throws Exception {
187    
188                    ExpandoRow expandoRow = ExpandoRowLocalServiceUtil.getRow(classPK);
189    
190                    DDMStorageLink ddmStorageLink =
191                            DDMStorageLinkLocalServiceUtil.getClassStorageLink(
192                                    expandoRow.getRowId());
193    
194                    ExpandoTable expandoTable = _getExpandoTable(
195                            expandoRow.getCompanyId(), ddmStorageLink.getStructureId(), fields);
196    
197                    List<ExpandoColumn> expandoColumns =
198                            ExpandoColumnLocalServiceUtil.getColumns(expandoTable.getTableId());
199    
200                    if (!mergeFields) {
201                            for (ExpandoColumn expandoColumn : expandoColumns) {
202                                    if (!fields.contains(expandoColumn.getName())) {
203                                            ExpandoValueLocalServiceUtil.deleteValue(
204                                                    expandoColumn.getColumnId(), expandoRow.getRowId());
205                                    }
206                            }
207                    }
208    
209                    _updateFields(expandoTable, expandoRow.getClassPK(), fields);
210            }
211    
212            private boolean _booleanValueOf(
213                    Expression expression, List<ExpandoValue> expandoValues) {
214    
215                    try {
216                            StandardEvaluationContext standardEvaluationContext =
217                                    new StandardEvaluationContext();
218    
219                            standardEvaluationContext.setBeanResolver(
220                                    new ExpandoValueBeanResolver(expandoValues));
221    
222                            return expression.getValue(
223                                    standardEvaluationContext, Boolean.class);
224                    }
225                    catch (EvaluationException ee) {
226                            _log.error("Unable to evaluate expression", ee);
227                    }
228    
229                    return false;
230            }
231    
232            private void _checkExpandoColumns(
233                            long ddmStructureId, ExpandoTable expandoTable, Fields fields)
234                    throws PortalException, SystemException {
235    
236                    for (String name : fields.getNames()) {
237                            ExpandoColumn expandoColumn =
238                                    ExpandoColumnLocalServiceUtil.getColumn(
239                                            expandoTable.getTableId(), name);
240    
241                            if (expandoColumn != null) {
242                                    continue;
243                            }
244    
245                            int type = _getExpandoColumnType(ddmStructureId, name);
246    
247                            ExpandoColumnLocalServiceUtil.addColumn(
248                                    expandoTable.getTableId(), name, type);
249                    }
250            }
251    
252            private List<Fields> _doQuery(
253                            long ddmStructureId, List<String> fieldNames, Condition condition,
254                            OrderByComparator orderByComparator)
255                    throws Exception {
256    
257                    return _doQuery(
258                            ddmStructureId, _getExpandoRowIds(ddmStructureId), fieldNames,
259                            condition, orderByComparator);
260            }
261    
262            private Map<Long, Fields> _doQuery(
263                            long ddmStructureId, long[] classPKs, List<String> fieldNames)
264                    throws Exception {
265    
266                    Map<Long, Fields> fieldsMap = new HashMap<Long, Fields>();
267    
268                    List<Fields> fieldsList = _doQuery(
269                            ddmStructureId, classPKs, fieldNames, null, null);
270    
271                    for (int i = 0; i < fieldsList.size(); i++) {
272                            Fields fields = fieldsList.get(i);
273    
274                            fieldsMap.put(classPKs[i], fields);
275                    }
276    
277                    return fieldsMap;
278            }
279    
280            private List<Fields> _doQuery(
281                            long ddmStructureId, long[] expandoRowIds, List<String> fieldNames,
282                            Condition condition, OrderByComparator orderByComparator)
283                    throws Exception {
284    
285                    List<Fields> fieldsList = new ArrayList<Fields>();
286    
287                    Expression expression = null;
288    
289                    if (condition != null) {
290                            expression = _parseExpression(condition);
291                    }
292    
293                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(
294                            ddmStructureId);
295    
296                    for (long expandoRowId : expandoRowIds) {
297                            List<ExpandoValue> expandoValues =
298                                    ExpandoValueLocalServiceUtil.getRowValues(expandoRowId);
299    
300                            if ((expression == null) ||
301                                    ((expression != null) &&
302                                     _booleanValueOf(expression, expandoValues))) {
303    
304                                    Fields fields = new Fields();
305    
306                                    for (ExpandoValue expandoValue : expandoValues) {
307                                            ExpandoColumn column = expandoValue.getColumn();
308    
309                                            String fieldName = column.getName();
310                                            Serializable fieldValue = expandoValue.getSerializable();
311    
312                                            if (ddmStructure.hasField(fieldName) &&
313                                                    ((fieldNames == null) ||
314                                                    ((fieldNames != null) &&
315                                                     fieldNames.contains(fieldName)))) {
316    
317                                                    Field field = new Field(
318                                                            ddmStructureId, fieldName, fieldValue);
319    
320                                                    fields.put(field);
321                                            }
322                                    }
323    
324                                    fieldsList.add(fields);
325                            }
326                    }
327    
328                    if (orderByComparator != null) {
329                            Collections.sort(fieldsList, orderByComparator);
330                    }
331    
332                    return fieldsList;
333            }
334    
335            private int _getExpandoColumnType(long ddmStructureId, String name)
336                    throws PortalException, SystemException {
337    
338                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(
339                            ddmStructureId);
340    
341                    String fieldDataType = ddmStructure.getFieldDataType(name);
342    
343                    if (fieldDataType.equals(FieldConstants.BOOLEAN)) {
344                            return ExpandoColumnConstants.BOOLEAN;
345                    }
346                    else if (fieldDataType.equals(FieldConstants.DATE)) {
347                            return ExpandoColumnConstants.DATE;
348                    }
349                    else if (fieldDataType.equals(FieldConstants.DOUBLE)) {
350                            return ExpandoColumnConstants.DOUBLE;
351                    }
352                    else if (fieldDataType.equals(FieldConstants.FLOAT)) {
353                            return ExpandoColumnConstants.FLOAT;
354                    }
355                    else if (fieldDataType.equals(FieldConstants.INTEGER)) {
356                            return ExpandoColumnConstants.INTEGER;
357                    }
358                    else if (fieldDataType.equals(FieldConstants.LONG)) {
359                            return ExpandoColumnConstants.LONG;
360                    }
361                    else if (fieldDataType.equals(FieldConstants.SHORT)) {
362                            return ExpandoColumnConstants.SHORT;
363                    }
364                    else {
365                            return ExpandoColumnConstants.STRING;
366                    }
367            }
368    
369            private long[] _getExpandoRowIds(long ddmStructureId)
370                    throws SystemException {
371    
372                    List<Long> expandoRowIds = new ArrayList<Long>();
373    
374                    List<DDMStorageLink> ddmStorageLinks =
375                            DDMStorageLinkLocalServiceUtil.getStructureStorageLinks(
376                                    ddmStructureId);
377    
378                    for (DDMStorageLink ddmStorageLink : ddmStorageLinks) {
379                            expandoRowIds.add(ddmStorageLink.getClassPK());
380                    }
381    
382                    return ArrayUtil.toArray(
383                            expandoRowIds.toArray(new Long[expandoRowIds.size()]));
384            }
385    
386            private ExpandoTable _getExpandoTable(
387                            long companyId, long ddmStructureId, Fields fields)
388                    throws PortalException, SystemException {
389    
390                    ExpandoTable expandoTable = null;
391    
392                    long classNameId = PortalUtil.getClassNameId(
393                            ExpandoStorageAdapter.class.getName());
394    
395                    try {
396                            expandoTable = ExpandoTableLocalServiceUtil.getTable(
397                                    companyId, classNameId, String.valueOf(ddmStructureId));
398                    }
399                    catch (NoSuchTableException nste) {
400                            expandoTable = ExpandoTableLocalServiceUtil.addTable(
401                                    companyId, classNameId, String.valueOf(ddmStructureId));
402                    }
403    
404                    _checkExpandoColumns(ddmStructureId, expandoTable, fields);
405    
406                    return expandoTable;
407            }
408    
409            private Expression _parseExpression(Condition condition) {
410                    String expression = _toExpression(condition);
411    
412                    try {
413                            ExpressionParser expressionParser = new SpelExpressionParser();
414    
415                            return expressionParser.parseExpression(expression);
416                    }
417                    catch (ParseException pe) {
418                            _log.error("Unable to parse expression " + expression, pe);
419                    }
420    
421                    return null;
422            }
423    
424            private String _toExpression(Condition condition) {
425                    if (condition.isJunction()) {
426                            Junction junction = (Junction)condition;
427    
428                            return StringPool.OPEN_PARENTHESIS.concat(
429                                    _toExpression(junction)).concat(StringPool.CLOSE_PARENTHESIS);
430                    }
431                    else {
432                            FieldCondition fieldCondition = (FieldCondition)condition;
433    
434                            return _toExpression(fieldCondition);
435                    }
436            }
437    
438            private String _toExpression(FieldCondition fieldCondition) {
439                    StringBundler sb = new StringBundler(5);
440    
441                    sb.append("(@");
442                    sb.append(fieldCondition.getName());
443    
444                    ComparisonOperator comparisonOperator =
445                            fieldCondition.getComparisonOperator();
446    
447                    if (comparisonOperator.equals(ComparisonOperator.LIKE)) {
448                            sb.append(".data matches ");
449                    }
450                    else {
451                            sb.append(".data == ");
452                    }
453    
454                    String value = StringUtil.quote(
455                            String.valueOf(fieldCondition.getValue()));
456    
457                    sb.append(value);
458                    sb.append(StringPool.CLOSE_PARENTHESIS);
459    
460                    return sb.toString();
461            }
462    
463            private String _toExpression(Junction junction) {
464                    StringBundler sb = new StringBundler();
465    
466                    LogicalOperator logicalOperator = junction.getLogicalOperator();
467    
468                    Iterator<Condition> itr = junction.iterator();
469    
470                    while (itr.hasNext()) {
471                            Condition condition = itr.next();
472    
473                            sb.append(_toExpression(condition));
474    
475                            if (itr.hasNext()) {
476                                    sb.append(StringPool.SPACE);
477                                    sb.append(logicalOperator.toString());
478                                    sb.append(StringPool.SPACE);
479                            }
480                    }
481    
482                    return sb.toString();
483            }
484    
485            private void _updateFields(
486                            ExpandoTable expandoTable, long classPK, Fields fields)
487                    throws PortalException, SystemException {
488    
489                    Iterator<Field> itr = fields.iterator();
490    
491                    while (itr.hasNext()) {
492                            Field field = itr.next();
493    
494                            ExpandoValueLocalServiceUtil.addValue(
495                                    expandoTable.getCompanyId(),
496                                    ExpandoStorageAdapter.class.getName(), expandoTable.getName(),
497                                    field.getName(), classPK, field.getValue());
498                    }
499            }
500    
501            private static Log _log = LogFactoryUtil.getLog(
502                    ExpandoStorageAdapter.class);
503    
504    }