001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.service.persistence.impl;
016    
017    import com.liferay.portal.NoSuchModelException;
018    import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
019    import com.liferay.portal.kernel.cache.PortalCache;
020    import com.liferay.portal.kernel.dao.jdbc.MappingSqlQuery;
021    import com.liferay.portal.kernel.dao.jdbc.MappingSqlQueryFactoryUtil;
022    import com.liferay.portal.kernel.dao.jdbc.RowMapper;
023    import com.liferay.portal.kernel.dao.jdbc.SqlUpdate;
024    import com.liferay.portal.kernel.dao.jdbc.SqlUpdateFactoryUtil;
025    import com.liferay.portal.kernel.exception.SystemException;
026    import com.liferay.portal.kernel.util.ListUtil;
027    import com.liferay.portal.kernel.util.OrderByComparator;
028    import com.liferay.portal.model.BaseModel;
029    import com.liferay.portal.model.ModelListener;
030    import com.liferay.portal.service.persistence.BasePersistence;
031    
032    import java.sql.Types;
033    
034    import java.util.ArrayList;
035    import java.util.Arrays;
036    import java.util.Collections;
037    import java.util.List;
038    
039    import javax.sql.DataSource;
040    
041    /**
042     * @author Shuyang Zhou
043     */
044    public class TableMapperImpl<L extends BaseModel<L>, R extends BaseModel<R>>
045            implements TableMapper<L, R> {
046    
047            public TableMapperImpl(
048                    String tableName, String leftColumnName, String rightColumnName,
049                    BasePersistence<L> leftBasePersistence,
050                    BasePersistence<R> rightBasePersistence) {
051    
052                    this.leftColumnName = leftColumnName;
053                    this.rightColumnName = rightColumnName;
054                    this.leftBasePersistence = leftBasePersistence;
055                    this.rightBasePersistence = rightBasePersistence;
056    
057                    DataSource dataSource = leftBasePersistence.getDataSource();
058    
059                    addTableMappingSqlUpdate = SqlUpdateFactoryUtil.getSqlUpdate(
060                            dataSource,
061                            "INSERT INTO " + tableName + " (" + leftColumnName + ", " +
062                                    rightColumnName + ") VALUES (?, ?)",
063                            new int[] {Types.BIGINT, Types.BIGINT});
064                    deleteLeftPrimaryKeyTableMappingsSqlUpdate =
065                            SqlUpdateFactoryUtil.getSqlUpdate(
066                                    dataSource,
067                                    "DELETE FROM " + tableName + " WHERE " + leftColumnName +
068                                            " = ?",
069                                    new int[] {Types.BIGINT});
070                    deleteRightPrimaryKeyTableMappingsSqlUpdate =
071                            SqlUpdateFactoryUtil.getSqlUpdate(
072                                    dataSource,
073                                    "DELETE FROM " + tableName + " WHERE " + rightColumnName +
074                                            " = ?",
075                                    new int[] {Types.BIGINT});
076                    deleteTableMappingSqlUpdate = SqlUpdateFactoryUtil.getSqlUpdate(
077                            dataSource,
078                            "DELETE FROM " + tableName + " WHERE " + leftColumnName +
079                                    " = ? AND " + rightColumnName + " = ?",
080                            new int[] {Types.BIGINT, Types.BIGINT});
081                    getLeftPrimaryKeysSqlQuery =
082                            MappingSqlQueryFactoryUtil.getMappingSqlQuery(
083                                    dataSource,
084                                    "SELECT " + leftColumnName + " FROM " + tableName + " WHERE " +
085                                            rightColumnName + " = ?",
086                                    new int[] {Types.BIGINT}, RowMapper.PRIMARY_KEY);
087                    getRightPrimaryKeysSqlQuery =
088                            MappingSqlQueryFactoryUtil.getMappingSqlQuery(
089                                    dataSource,
090                                    "SELECT " + rightColumnName + " FROM " + tableName + " WHERE " +
091                                            leftColumnName + " = ?",
092                                    new int[] {Types.BIGINT}, RowMapper.PRIMARY_KEY);
093                    leftToRightPortalCache = MultiVMPoolUtil.getCache(
094                            TableMapper.class.getName() + "-" + tableName + "-LeftToRight");
095                    rightToLeftPortalCache = MultiVMPoolUtil.getCache(
096                            TableMapper.class.getName() + "-" + tableName + "-RightToLeft");
097            }
098    
099            @Override
100            public boolean addTableMapping(long leftPrimaryKey, long rightPrimaryKey)
101                    throws SystemException {
102    
103                    if (containsTableMapping(leftPrimaryKey, rightPrimaryKey, false)) {
104                            return false;
105                    }
106    
107                    leftToRightPortalCache.remove(leftPrimaryKey);
108                    rightToLeftPortalCache.remove(rightPrimaryKey);
109    
110                    Class<R> rightModelClass = rightBasePersistence.getModelClass();
111    
112                    ModelListener<L>[] leftModelListeners =
113                            leftBasePersistence.getListeners();
114    
115                    for (ModelListener<L> leftModelListener : leftModelListeners) {
116                            leftModelListener.onBeforeAddAssociation(
117                                    leftPrimaryKey, rightModelClass.getName(), rightPrimaryKey);
118                    }
119    
120                    Class<L> leftModelClass = leftBasePersistence.getModelClass();
121    
122                    ModelListener<R>[] rightModelListeners =
123                            rightBasePersistence.getListeners();
124    
125                    for (ModelListener<R> rightModelListener : rightModelListeners) {
126                            rightModelListener.onBeforeAddAssociation(
127                                    rightPrimaryKey, leftModelClass.getName(), leftPrimaryKey);
128                    }
129    
130                    try {
131                            addTableMappingSqlUpdate.update(leftPrimaryKey, rightPrimaryKey);
132                    }
133                    catch (Exception e) {
134                            throw new SystemException(e);
135                    }
136    
137                    for (ModelListener<L> leftModelListener : leftModelListeners) {
138                            leftModelListener.onAfterAddAssociation(
139                                    leftPrimaryKey, rightModelClass.getName(), rightPrimaryKey);
140                    }
141    
142                    for (ModelListener<R> rightModelListener : rightModelListeners) {
143                            rightModelListener.onAfterAddAssociation(
144                                    rightPrimaryKey, leftModelClass.getName(), leftPrimaryKey);
145                    }
146    
147                    return true;
148            }
149    
150            @Override
151            public boolean containsTableMapping(
152                            long leftPrimaryKey, long rightPrimaryKey)
153                    throws SystemException {
154    
155                    return containsTableMapping(leftPrimaryKey, rightPrimaryKey, true);
156            }
157    
158            @Override
159            public int deleteLeftPrimaryKeyTableMappings(long leftPrimaryKey)
160                    throws SystemException {
161    
162                    return deleteTableMappings(
163                            leftBasePersistence, rightBasePersistence, leftToRightPortalCache,
164                            rightToLeftPortalCache, getRightPrimaryKeysSqlQuery,
165                            deleteLeftPrimaryKeyTableMappingsSqlUpdate, leftPrimaryKey);
166            }
167    
168            @Override
169            public int deleteRightPrimaryKeyTableMappings(long rightPrimaryKey)
170                    throws SystemException {
171    
172                    return deleteTableMappings(
173                            rightBasePersistence, leftBasePersistence, rightToLeftPortalCache,
174                            leftToRightPortalCache, getLeftPrimaryKeysSqlQuery,
175                            deleteRightPrimaryKeyTableMappingsSqlUpdate, rightPrimaryKey);
176            }
177    
178            @Override
179            public boolean deleteTableMapping(long leftPrimaryKey, long rightPrimaryKey)
180                    throws SystemException {
181    
182                    if (!containsTableMapping(leftPrimaryKey, rightPrimaryKey, false)) {
183                            return false;
184                    }
185    
186                    leftToRightPortalCache.remove(leftPrimaryKey);
187                    rightToLeftPortalCache.remove(rightPrimaryKey);
188    
189                    Class<R> rightModelClass = rightBasePersistence.getModelClass();
190    
191                    ModelListener<L>[] leftModelListeners =
192                            leftBasePersistence.getListeners();
193    
194                    for (ModelListener<L> leftModelListener : leftModelListeners) {
195                            leftModelListener.onBeforeRemoveAssociation(
196                                    leftPrimaryKey, rightModelClass.getName(), rightPrimaryKey);
197                    }
198    
199                    Class<L> leftModelClass = leftBasePersistence.getModelClass();
200    
201                    ModelListener<R>[] rightModelListeners =
202                            rightBasePersistence.getListeners();
203    
204                    for (ModelListener<R> rightModelListener : rightModelListeners) {
205                            rightModelListener.onBeforeRemoveAssociation(
206                                    rightPrimaryKey, leftModelClass.getName(), leftPrimaryKey);
207                    }
208    
209                    int rowCount = 0;
210    
211                    try {
212                            rowCount = deleteTableMappingSqlUpdate.update(
213                                    leftPrimaryKey, rightPrimaryKey);
214                    }
215                    catch (Exception e) {
216                            throw new SystemException(e);
217                    }
218    
219                    if (rowCount > 0) {
220                            for (ModelListener<L> leftModelListener : leftModelListeners) {
221                                    leftModelListener.onAfterRemoveAssociation(
222                                            leftPrimaryKey, rightModelClass.getName(), rightPrimaryKey);
223                            }
224    
225                            for (ModelListener<R> rightModelListener : rightModelListeners) {
226                                    rightModelListener.onAfterRemoveAssociation(
227                                            rightPrimaryKey, leftModelClass.getName(), leftPrimaryKey);
228                            }
229    
230                            return true;
231                    }
232    
233                    return false;
234            }
235    
236            @Override
237            public void destroy() {
238                    MultiVMPoolUtil.removeCache(leftToRightPortalCache.getName());
239                    MultiVMPoolUtil.removeCache(rightToLeftPortalCache.getName());
240            }
241    
242            @Override
243            public List<L> getLeftBaseModels(
244                            long rightPrimaryKey, int start, int end, OrderByComparator obc)
245                    throws SystemException {
246    
247                    return getBaseModels(
248                            rightToLeftPortalCache, getLeftPrimaryKeysSqlQuery, rightPrimaryKey,
249                            leftBasePersistence, start, end, obc);
250            }
251    
252            @Override
253            public long[] getLeftPrimaryKeys(long rightPrimaryKey)
254                    throws SystemException {
255    
256                    return getPrimaryKeys(
257                            rightToLeftPortalCache, getLeftPrimaryKeysSqlQuery, rightPrimaryKey,
258                            true);
259            }
260    
261            @Override
262            public TableMapper<R, L> getReverseTableMapper() {
263                    return reverseTableMapper;
264            }
265    
266            @Override
267            public List<R> getRightBaseModels(
268                            long leftPrimaryKey, int start, int end, OrderByComparator obc)
269                    throws SystemException {
270    
271                    return getBaseModels(
272                            leftToRightPortalCache, getRightPrimaryKeysSqlQuery, leftPrimaryKey,
273                            rightBasePersistence, start, end, obc);
274            }
275    
276            @Override
277            public long[] getRightPrimaryKeys(long leftPrimaryKey)
278                    throws SystemException {
279    
280                    return getPrimaryKeys(
281                            leftToRightPortalCache, getRightPrimaryKeysSqlQuery, leftPrimaryKey,
282                            true);
283            }
284    
285            @Override
286            public boolean matches(String leftColumnName, String rightColumnName) {
287                    if (this.leftColumnName.equals(leftColumnName) &&
288                            this.rightColumnName.equals(rightColumnName)) {
289    
290                            return true;
291                    }
292    
293                    return false;
294            }
295    
296            public void setReverseTableMapper(TableMapper<R, L> reverseTableMapper) {
297                    this.reverseTableMapper = reverseTableMapper;
298            }
299    
300            protected static <M extends BaseModel<M>, S extends BaseModel<S>> int
301                    deleteTableMappings(
302                            BasePersistence<M> masterBasePersistence,
303                            BasePersistence<S> slaveBasePersistence,
304                            PortalCache<Long, long[]> masterToSlavePortalCache,
305                            PortalCache<Long, long[]> slaveToMasterPortalCache,
306                            MappingSqlQuery<Long> mappingSqlQuery, SqlUpdate deleteSqlUpdate,
307                            long masterPrimaryKey)
308                    throws SystemException {
309    
310                    ModelListener<M>[] masterModelListeners =
311                            masterBasePersistence.getListeners();
312                    ModelListener<S>[] slaveModelListeners =
313                            slaveBasePersistence.getListeners();
314    
315                    long[] slavePrimaryKeys = getPrimaryKeys(
316                            masterToSlavePortalCache, mappingSqlQuery, masterPrimaryKey, false);
317    
318                    Class<M> masterModelClass = null;
319                    Class<S> slaveModelClass = null;
320    
321                    if ((masterModelListeners.length > 0) ||
322                            (slaveModelListeners.length > 0)) {
323    
324                            masterModelClass = masterBasePersistence.getModelClass();
325                            slaveModelClass = slaveBasePersistence.getModelClass();
326    
327                            for (long slavePrimaryKey : slavePrimaryKeys) {
328                                    for (ModelListener<M> masterModelListener :
329                                                    masterModelListeners) {
330    
331                                            masterModelListener.onBeforeRemoveAssociation(
332                                                    masterPrimaryKey, slaveModelClass.getName(),
333                                                    slavePrimaryKey);
334                                    }
335    
336                                    for (ModelListener<S> slaveModelListener :
337                                                    slaveModelListeners) {
338    
339                                            slaveModelListener.onBeforeRemoveAssociation(
340                                                    slavePrimaryKey, masterModelClass.getName(),
341                                                    masterPrimaryKey);
342                                    }
343                            }
344                    }
345    
346                    masterToSlavePortalCache.remove(masterPrimaryKey);
347    
348                    for (long slavePrimaryKey : slavePrimaryKeys) {
349                            slaveToMasterPortalCache.remove(slavePrimaryKey);
350                    }
351    
352                    int rowCount = 0;
353    
354                    try {
355                            rowCount = deleteSqlUpdate.update(masterPrimaryKey);
356                    }
357                    catch (Exception e) {
358                            throw new SystemException(e);
359                    }
360    
361                    if ((masterModelListeners.length > 0) ||
362                            (slaveModelListeners.length > 0)) {
363    
364                            for (long slavePrimaryKey : slavePrimaryKeys) {
365                                    for (ModelListener<M> masterModelListener :
366                                                    masterModelListeners) {
367    
368                                            masterModelListener.onAfterRemoveAssociation(
369                                                    masterPrimaryKey, slaveModelClass.getName(),
370                                                    slavePrimaryKey);
371                                    }
372    
373                                    for (ModelListener<S> slaveModelListener :
374                                                    slaveModelListeners) {
375    
376                                            slaveModelListener.onAfterRemoveAssociation(
377                                                    slavePrimaryKey, masterModelClass.getName(),
378                                                    masterPrimaryKey);
379                                    }
380                            }
381                    }
382    
383                    return rowCount;
384            }
385    
386            protected static <T extends BaseModel<T>> List<T>
387                    getBaseModels(
388                            PortalCache<Long, long[]> portalCache,
389                            MappingSqlQuery<Long> mappingSqlQuery, long masterPrimaryKey,
390                            BasePersistence<T> slaveBasePersistence, int start, int end,
391                            OrderByComparator obc)
392                    throws SystemException {
393    
394                    long[] slavePrimaryKeys = getPrimaryKeys(
395                            portalCache, mappingSqlQuery, masterPrimaryKey, true);
396    
397                    if (slavePrimaryKeys.length == 0) {
398                            return Collections.emptyList();
399                    }
400    
401                    List<T> slaveBaseModels = new ArrayList<T>(slavePrimaryKeys.length);
402    
403                    try {
404                            for (long slavePrimaryKey : slavePrimaryKeys) {
405                                    slaveBaseModels.add(
406                                            slaveBasePersistence.findByPrimaryKey(slavePrimaryKey));
407                            }
408                    }
409                    catch (NoSuchModelException nsme) {
410                            throw new SystemException(nsme);
411                    }
412    
413                    if (obc != null) {
414                            Collections.sort(slaveBaseModels, obc);
415                    }
416    
417                    return ListUtil.subList(slaveBaseModels, start, end);
418            }
419    
420            protected static long[] getPrimaryKeys(
421                            PortalCache<Long, long[]> portalCache,
422                            MappingSqlQuery<Long> mappingSqlQuery, long masterPrimaryKey,
423                            boolean updateCache)
424                    throws SystemException {
425    
426                    long[] primaryKeys = portalCache.get(masterPrimaryKey);
427    
428                    if (primaryKeys == null) {
429                            List<Long> primaryKeysList = null;
430    
431                            try {
432                                    primaryKeysList = mappingSqlQuery.execute(masterPrimaryKey);
433                            }
434                            catch (Exception e) {
435                                    throw new SystemException(e);
436                            }
437    
438                            primaryKeys = new long[primaryKeysList.size()];
439    
440                            for (int i = 0; i < primaryKeys.length; i++) {
441                                    primaryKeys[i] = primaryKeysList.get(i);
442                            }
443    
444                            Arrays.sort(primaryKeys);
445    
446                            if (updateCache) {
447                                    portalCache.put(masterPrimaryKey, primaryKeys);
448                            }
449                    }
450    
451                    return primaryKeys;
452            }
453    
454            protected boolean containsTableMapping(
455                            long leftPrimaryKey, long rightPrimaryKey, boolean updateCache)
456                    throws SystemException {
457    
458                    long[] rightPrimaryKeys = getPrimaryKeys(
459                            leftToRightPortalCache, getRightPrimaryKeysSqlQuery, leftPrimaryKey,
460                            updateCache);
461    
462                    if (Arrays.binarySearch(rightPrimaryKeys, rightPrimaryKey) < 0) {
463                            return false;
464                    }
465                    else {
466                            return true;
467                    }
468            }
469    
470            protected SqlUpdate addTableMappingSqlUpdate;
471            protected SqlUpdate deleteLeftPrimaryKeyTableMappingsSqlUpdate;
472            protected SqlUpdate deleteRightPrimaryKeyTableMappingsSqlUpdate;
473            protected SqlUpdate deleteTableMappingSqlUpdate;
474            protected MappingSqlQuery<Long> getLeftPrimaryKeysSqlQuery;
475            protected MappingSqlQuery<Long> getRightPrimaryKeysSqlQuery;
476            protected BasePersistence<L> leftBasePersistence;
477            protected String leftColumnName;
478            protected PortalCache<Long, long[]> leftToRightPortalCache;
479            protected TableMapper<R, L> reverseTableMapper;
480            protected BasePersistence<R> rightBasePersistence;
481            protected String rightColumnName;
482            protected PortalCache<Long, long[]> rightToLeftPortalCache;
483    
484    }