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 List<L> getLeftBaseModels(
238                            long rightPrimaryKey, int start, int end, OrderByComparator obc)
239                    throws SystemException {
240    
241                    return getBaseModels(
242                            rightToLeftPortalCache, getLeftPrimaryKeysSqlQuery, rightPrimaryKey,
243                            leftBasePersistence, start, end, obc);
244            }
245    
246            @Override
247            public long[] getLeftPrimaryKeys(long rightPrimaryKey)
248                    throws SystemException {
249    
250                    return getPrimaryKeys(
251                            rightToLeftPortalCache, getLeftPrimaryKeysSqlQuery, rightPrimaryKey,
252                            true);
253            }
254    
255            @Override
256            public TableMapper<R, L> getReverseTableMapper() {
257                    return reverseTableMapper;
258            }
259    
260            @Override
261            public List<R> getRightBaseModels(
262                            long leftPrimaryKey, int start, int end, OrderByComparator obc)
263                    throws SystemException {
264    
265                    return getBaseModels(
266                            leftToRightPortalCache, getRightPrimaryKeysSqlQuery, leftPrimaryKey,
267                            rightBasePersistence, start, end, obc);
268            }
269    
270            @Override
271            public long[] getRightPrimaryKeys(long leftPrimaryKey)
272                    throws SystemException {
273    
274                    return getPrimaryKeys(
275                            leftToRightPortalCache, getRightPrimaryKeysSqlQuery, leftPrimaryKey,
276                            true);
277            }
278    
279            @Override
280            public boolean matches(String leftColumnName, String rightColumnName) {
281                    if (this.leftColumnName.equals(leftColumnName) &&
282                            this.rightColumnName.equals(rightColumnName)) {
283    
284                            return true;
285                    }
286    
287                    return false;
288            }
289    
290            public void setReverseTableMapper(TableMapper<R, L> reverseTableMapper) {
291                    this.reverseTableMapper = reverseTableMapper;
292            }
293    
294            protected static <M extends BaseModel<M>, S extends BaseModel<S>> int
295                    deleteTableMappings(
296                            BasePersistence<M> masterBasePersistence,
297                            BasePersistence<S> slaveBasePersistence,
298                            PortalCache<Long, long[]> masterToSlavePortalCache,
299                            PortalCache<Long, long[]> slaveToMasterPortalCache,
300                            MappingSqlQuery<Long> mappingSqlQuery, SqlUpdate deleteSqlUpdate,
301                            long masterPrimaryKey)
302                    throws SystemException {
303    
304                    ModelListener<M>[] masterModelListeners =
305                            masterBasePersistence.getListeners();
306                    ModelListener<S>[] slaveModelListeners =
307                            slaveBasePersistence.getListeners();
308    
309                    long[] slavePrimaryKeys = getPrimaryKeys(
310                            masterToSlavePortalCache, mappingSqlQuery, masterPrimaryKey, false);
311    
312                    Class<M> masterModelClass = null;
313                    Class<S> slaveModelClass = null;
314    
315                    if ((masterModelListeners.length > 0) ||
316                            (slaveModelListeners.length > 0)) {
317    
318                            masterModelClass = masterBasePersistence.getModelClass();
319                            slaveModelClass = slaveBasePersistence.getModelClass();
320    
321                            for (long slavePrimaryKey : slavePrimaryKeys) {
322                                    for (ModelListener<M> masterModelListener :
323                                                    masterModelListeners) {
324    
325                                            masterModelListener.onBeforeRemoveAssociation(
326                                                    masterPrimaryKey, slaveModelClass.getName(),
327                                                    slavePrimaryKey);
328                                    }
329    
330                                    for (ModelListener<S> slaveModelListener :
331                                                    slaveModelListeners) {
332    
333                                            slaveModelListener.onBeforeRemoveAssociation(
334                                                    slavePrimaryKey, masterModelClass.getName(),
335                                                    masterPrimaryKey);
336                                    }
337                            }
338                    }
339    
340                    masterToSlavePortalCache.remove(masterPrimaryKey);
341    
342                    for (long slavePrimaryKey : slavePrimaryKeys) {
343                            slaveToMasterPortalCache.remove(slavePrimaryKey);
344                    }
345    
346                    int rowCount = 0;
347    
348                    try {
349                            rowCount = deleteSqlUpdate.update(masterPrimaryKey);
350                    }
351                    catch (Exception e) {
352                            throw new SystemException(e);
353                    }
354    
355                    if ((masterModelListeners.length > 0) ||
356                            (slaveModelListeners.length > 0)) {
357    
358                            for (long slavePrimaryKey : slavePrimaryKeys) {
359                                    for (ModelListener<M> masterModelListener :
360                                                    masterModelListeners) {
361    
362                                            masterModelListener.onAfterRemoveAssociation(
363                                                    masterPrimaryKey, slaveModelClass.getName(),
364                                                    slavePrimaryKey);
365                                    }
366    
367                                    for (ModelListener<S> slaveModelListener :
368                                                    slaveModelListeners) {
369    
370                                            slaveModelListener.onAfterRemoveAssociation(
371                                                    slavePrimaryKey, masterModelClass.getName(),
372                                                    masterPrimaryKey);
373                                    }
374                            }
375                    }
376    
377                    return rowCount;
378            }
379    
380            protected static <T extends BaseModel<T>> List<T>
381                    getBaseModels(
382                            PortalCache<Long, long[]> portalCache,
383                            MappingSqlQuery<Long> mappingSqlQuery, long masterPrimaryKey,
384                            BasePersistence<T> slaveBasePersistence, int start, int end,
385                            OrderByComparator obc)
386                    throws SystemException {
387    
388                    long[] slavePrimaryKeys = getPrimaryKeys(
389                            portalCache, mappingSqlQuery, masterPrimaryKey, true);
390    
391                    if (slavePrimaryKeys.length == 0) {
392                            return Collections.emptyList();
393                    }
394    
395                    List<T> slaveBaseModels = new ArrayList<T>(slavePrimaryKeys.length);
396    
397                    try {
398                            for (long slavePrimaryKey : slavePrimaryKeys) {
399                                    slaveBaseModels.add(
400                                            slaveBasePersistence.findByPrimaryKey(slavePrimaryKey));
401                            }
402                    }
403                    catch (NoSuchModelException nsme) {
404                            throw new SystemException(nsme);
405                    }
406    
407                    if (obc != null) {
408                            Collections.sort(slaveBaseModels, obc);
409                    }
410    
411                    return ListUtil.subList(slaveBaseModels, start, end);
412            }
413    
414            protected static long[] getPrimaryKeys(
415                            PortalCache<Long, long[]> portalCache,
416                            MappingSqlQuery<Long> mappingSqlQuery, long masterPrimaryKey,
417                            boolean updateCache)
418                    throws SystemException {
419    
420                    long[] primaryKeys = portalCache.get(masterPrimaryKey);
421    
422                    if (primaryKeys == null) {
423                            List<Long> primaryKeysList = null;
424    
425                            try {
426                                    primaryKeysList = mappingSqlQuery.execute(masterPrimaryKey);
427                            }
428                            catch (Exception e) {
429                                    throw new SystemException(e);
430                            }
431    
432                            primaryKeys = new long[primaryKeysList.size()];
433    
434                            for (int i = 0; i < primaryKeys.length; i++) {
435                                    primaryKeys[i] = primaryKeysList.get(i);
436                            }
437    
438                            Arrays.sort(primaryKeys);
439    
440                            if (updateCache) {
441                                    portalCache.put(masterPrimaryKey, primaryKeys);
442                            }
443                    }
444    
445                    return primaryKeys;
446            }
447    
448            protected boolean containsTableMapping(
449                            long leftPrimaryKey, long rightPrimaryKey, boolean updateCache)
450                    throws SystemException {
451    
452                    long[] rightPrimaryKeys = getPrimaryKeys(
453                            leftToRightPortalCache, getRightPrimaryKeysSqlQuery, leftPrimaryKey,
454                            updateCache);
455    
456                    if (Arrays.binarySearch(rightPrimaryKeys, rightPrimaryKey) < 0) {
457                            return false;
458                    }
459                    else {
460                            return true;
461                    }
462            }
463    
464            protected SqlUpdate addTableMappingSqlUpdate;
465            protected SqlUpdate deleteLeftPrimaryKeyTableMappingsSqlUpdate;
466            protected SqlUpdate deleteRightPrimaryKeyTableMappingsSqlUpdate;
467            protected SqlUpdate deleteTableMappingSqlUpdate;
468            protected MappingSqlQuery<Long> getLeftPrimaryKeysSqlQuery;
469            protected MappingSqlQuery<Long> getRightPrimaryKeysSqlQuery;
470            protected BasePersistence<L> leftBasePersistence;
471            protected String leftColumnName;
472            protected PortalCache<Long, long[]> leftToRightPortalCache;
473            protected TableMapper<R, L> reverseTableMapper;
474            protected BasePersistence<R> rightBasePersistence;
475            protected String rightColumnName;
476            protected PortalCache<Long, long[]> rightToLeftPortalCache;
477    
478    }