001
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.cache.PortalCacheHelperUtil;
021 import com.liferay.portal.kernel.dao.jdbc.MappingSqlQuery;
022 import com.liferay.portal.kernel.dao.jdbc.MappingSqlQueryFactoryUtil;
023 import com.liferay.portal.kernel.dao.jdbc.RowMapper;
024 import com.liferay.portal.kernel.dao.jdbc.SqlUpdate;
025 import com.liferay.portal.kernel.dao.jdbc.SqlUpdateFactoryUtil;
026 import com.liferay.portal.kernel.exception.SystemException;
027 import com.liferay.portal.kernel.util.ListUtil;
028 import com.liferay.portal.kernel.util.OrderByComparator;
029 import com.liferay.portal.model.BaseModel;
030 import com.liferay.portal.model.ModelListener;
031 import com.liferay.portal.service.persistence.BasePersistence;
032
033 import java.sql.Types;
034
035 import java.util.ArrayList;
036 import java.util.Arrays;
037 import java.util.Collections;
038 import java.util.Iterator;
039 import java.util.List;
040 import java.util.Map;
041 import java.util.Map.Entry;
042 import java.util.Set;
043 import java.util.concurrent.ConcurrentHashMap;
044
045 import javax.sql.DataSource;
046
047
050 public class TableMapperImpl<L extends BaseModel<L>, R extends BaseModel<R>>
051 implements TableMapper<L, R> {
052
053 public TableMapperImpl(
054 String tableName, String companyColumnName, String leftColumnName,
055 String rightColumnName, BasePersistence<L> leftBasePersistence,
056 BasePersistence<R> rightBasePersistence) {
057
058 this.tableName = tableName;
059 this.companyColumnName = companyColumnName;
060 this.leftColumnName = leftColumnName;
061 this.rightColumnName = rightColumnName;
062 this.leftBasePersistence = leftBasePersistence;
063 this.rightBasePersistence = rightBasePersistence;
064
065 DataSource dataSource = leftBasePersistence.getDataSource();
066
067 addTableMappingSqlUpdate = SqlUpdateFactoryUtil.getSqlUpdate(
068 dataSource,
069 "INSERT INTO " + tableName + " (" + companyColumnName + ", " +
070 leftColumnName + ", " + rightColumnName + ") VALUES (?, ?, ?)",
071 new int[] {Types.BIGINT, Types.BIGINT, Types.BIGINT});
072 deleteLeftPrimaryKeyTableMappingsSqlUpdate =
073 SqlUpdateFactoryUtil.getSqlUpdate(
074 dataSource,
075 "DELETE FROM " + tableName + " WHERE " + companyColumnName +
076 " = ? AND " +leftColumnName + " = ?",
077 new int[] {Types.BIGINT, Types.BIGINT});
078 deleteRightPrimaryKeyTableMappingsSqlUpdate =
079 SqlUpdateFactoryUtil.getSqlUpdate(
080 dataSource,
081 "DELETE FROM " + tableName + " WHERE " + companyColumnName +
082 " = ? AND " + rightColumnName + " = ?",
083 new int[] {Types.BIGINT, Types.BIGINT});
084 deleteTableMappingSqlUpdate = SqlUpdateFactoryUtil.getSqlUpdate(
085 dataSource,
086 "DELETE FROM " + tableName + " WHERE " + companyColumnName +
087 " = ? AND " + leftColumnName + " = ? AND " + rightColumnName +
088 " = ?",
089 new int[] {Types.BIGINT, Types.BIGINT, Types.BIGINT});
090 getLeftPrimaryKeysSqlQuery =
091 MappingSqlQueryFactoryUtil.getMappingSqlQuery(
092 dataSource,
093 "SELECT " + leftColumnName + " FROM " + tableName + " WHERE " +
094 companyColumnName + " = ? AND " + rightColumnName + " = ?",
095 new int[] {Types.BIGINT, Types.BIGINT}, RowMapper.PRIMARY_KEY);
096 getRightPrimaryKeysSqlQuery =
097 MappingSqlQueryFactoryUtil.getMappingSqlQuery(
098 dataSource,
099 "SELECT " + rightColumnName + " FROM " + tableName + " WHERE " +
100 companyColumnName + " = ? AND " + leftColumnName + " = ?",
101 new int[] {Types.BIGINT, Types.BIGINT}, RowMapper.PRIMARY_KEY);
102 }
103
104 @Override
105 public boolean addTableMapping(
106 long companyId, long leftPrimaryKey, long rightPrimaryKey) {
107
108 if (containsTableMapping(
109 companyId, leftPrimaryKey, rightPrimaryKey, false)) {
110
111 return false;
112 }
113
114 PortalCache<Long, long[]> leftToRightPortalCache =
115 getLeftToRightPortalCache(companyId);
116
117 leftToRightPortalCache.remove(leftPrimaryKey);
118
119 PortalCache<Long, long[]> rightToLeftPortalCache =
120 getRightToLeftPortalCache(companyId);
121
122 rightToLeftPortalCache.remove(rightPrimaryKey);
123
124 Class<R> rightModelClass = rightBasePersistence.getModelClass();
125
126 ModelListener<L>[] leftModelListeners =
127 leftBasePersistence.getListeners();
128
129 for (ModelListener<L> leftModelListener : leftModelListeners) {
130 leftModelListener.onBeforeAddAssociation(
131 leftPrimaryKey, rightModelClass.getName(), rightPrimaryKey);
132 }
133
134 Class<L> leftModelClass = leftBasePersistence.getModelClass();
135
136 ModelListener<R>[] rightModelListeners =
137 rightBasePersistence.getListeners();
138
139 for (ModelListener<R> rightModelListener : rightModelListeners) {
140 rightModelListener.onBeforeAddAssociation(
141 rightPrimaryKey, leftModelClass.getName(), leftPrimaryKey);
142 }
143
144 try {
145 addTableMappingSqlUpdate.update(
146 companyId, leftPrimaryKey, rightPrimaryKey);
147 }
148 catch (Exception e) {
149 throw new SystemException(e);
150 }
151
152 for (ModelListener<L> leftModelListener : leftModelListeners) {
153 leftModelListener.onAfterAddAssociation(
154 leftPrimaryKey, rightModelClass.getName(), rightPrimaryKey);
155 }
156
157 for (ModelListener<R> rightModelListener : rightModelListeners) {
158 rightModelListener.onAfterAddAssociation(
159 rightPrimaryKey, leftModelClass.getName(), leftPrimaryKey);
160 }
161
162 return true;
163 }
164
165 @Override
166 public boolean containsTableMapping(
167 long companyId, long leftPrimaryKey, long rightPrimaryKey) {
168
169 return containsTableMapping(
170 companyId, leftPrimaryKey, rightPrimaryKey, true);
171 }
172
173 @Override
174 public int deleteLeftPrimaryKeyTableMappings(
175 long companyId, long leftPrimaryKey) {
176
177 return deleteTableMappings(
178 leftBasePersistence, rightBasePersistence,
179 getLeftToRightPortalCache(companyId),
180 getRightToLeftPortalCache(companyId), getRightPrimaryKeysSqlQuery,
181 deleteLeftPrimaryKeyTableMappingsSqlUpdate, companyId,
182 leftPrimaryKey);
183 }
184
185 @Override
186 public int deleteRightPrimaryKeyTableMappings(
187 long companyId, long rightPrimaryKey) {
188
189 return deleteTableMappings(
190 rightBasePersistence, leftBasePersistence,
191 getRightToLeftPortalCache(companyId),
192 getLeftToRightPortalCache(companyId), getLeftPrimaryKeysSqlQuery,
193 deleteRightPrimaryKeyTableMappingsSqlUpdate, companyId,
194 rightPrimaryKey);
195 }
196
197 @Override
198 public boolean deleteTableMapping(
199 long companyId, long leftPrimaryKey, long rightPrimaryKey) {
200
201 if (!containsTableMapping(
202 companyId, leftPrimaryKey, rightPrimaryKey, false)) {
203
204 return false;
205 }
206
207 PortalCache<Long, long[]> leftToRightPortalCache =
208 getLeftToRightPortalCache(companyId);
209
210 leftToRightPortalCache.remove(leftPrimaryKey);
211
212 PortalCache<Long, long[]> rightToLeftPortalCache =
213 getRightToLeftPortalCache(companyId);
214
215 rightToLeftPortalCache.remove(rightPrimaryKey);
216
217 Class<R> rightModelClass = rightBasePersistence.getModelClass();
218
219 ModelListener<L>[] leftModelListeners =
220 leftBasePersistence.getListeners();
221
222 for (ModelListener<L> leftModelListener : leftModelListeners) {
223 leftModelListener.onBeforeRemoveAssociation(
224 leftPrimaryKey, rightModelClass.getName(), rightPrimaryKey);
225 }
226
227 Class<L> leftModelClass = leftBasePersistence.getModelClass();
228
229 ModelListener<R>[] rightModelListeners =
230 rightBasePersistence.getListeners();
231
232 for (ModelListener<R> rightModelListener : rightModelListeners) {
233 rightModelListener.onBeforeRemoveAssociation(
234 rightPrimaryKey, leftModelClass.getName(), leftPrimaryKey);
235 }
236
237 int rowCount = 0;
238
239 try {
240 rowCount = deleteTableMappingSqlUpdate.update(
241 companyId, leftPrimaryKey, rightPrimaryKey);
242 }
243 catch (Exception e) {
244 throw new SystemException(e);
245 }
246
247 if (rowCount > 0) {
248 for (ModelListener<L> leftModelListener : leftModelListeners) {
249 leftModelListener.onAfterRemoveAssociation(
250 leftPrimaryKey, rightModelClass.getName(), rightPrimaryKey);
251 }
252
253 for (ModelListener<R> rightModelListener : rightModelListeners) {
254 rightModelListener.onAfterRemoveAssociation(
255 rightPrimaryKey, leftModelClass.getName(), leftPrimaryKey);
256 }
257
258 return true;
259 }
260
261 return false;
262 }
263
264 @Override
265 public void destroy() {
266 Set<Entry<Long, String>> set = _leftToRightPortalCacheNames.entrySet();
267
268 Iterator<Entry<Long, String>> iterator = set.iterator();
269
270 while (iterator.hasNext()) {
271 Entry<Long, String> entry = iterator.next();
272
273 MultiVMPoolUtil.removePortalCache(entry.getValue());
274
275 iterator.remove();
276 }
277
278 set = _rightToLeftPortalCacheNames.entrySet();
279
280 iterator = set.iterator();
281
282 while (iterator.hasNext()) {
283 Entry<Long, String> entry = iterator.next();
284
285 MultiVMPoolUtil.removePortalCache(entry.getValue());
286
287 iterator.remove();
288 }
289 }
290
291 @Override
292 public List<L> getLeftBaseModels(
293 long companyId, long rightPrimaryKey, int start, int end,
294 OrderByComparator<L> obc) {
295
296 return getBaseModels(
297 getRightToLeftPortalCache(companyId), getLeftPrimaryKeysSqlQuery,
298 companyId, rightPrimaryKey, leftBasePersistence, start, end, obc);
299 }
300
301 @Override
302 public long[] getLeftPrimaryKeys(long companyId, long rightPrimaryKey) {
303 return getPrimaryKeys(
304 getRightToLeftPortalCache(companyId), getLeftPrimaryKeysSqlQuery,
305 companyId, rightPrimaryKey, true);
306 }
307
308 @Override
309 public TableMapper<R, L> getReverseTableMapper() {
310 return reverseTableMapper;
311 }
312
313 @Override
314 public List<R> getRightBaseModels(
315 long companyId, long leftPrimaryKey, int start, int end,
316 OrderByComparator<R> obc) {
317
318 return getBaseModels(
319 getLeftToRightPortalCache(companyId), getRightPrimaryKeysSqlQuery,
320 companyId, leftPrimaryKey, rightBasePersistence, start, end, obc);
321 }
322
323 @Override
324 public long[] getRightPrimaryKeys(long companyId, long leftPrimaryKey) {
325 return getPrimaryKeys(
326 getLeftToRightPortalCache(companyId), getRightPrimaryKeysSqlQuery,
327 companyId, leftPrimaryKey, true);
328 }
329
330 @Override
331 public boolean matches(String leftColumnName, String rightColumnName) {
332 if (this.leftColumnName.equals(leftColumnName) &&
333 this.rightColumnName.equals(rightColumnName)) {
334
335 return true;
336 }
337
338 return false;
339 }
340
341 public void setReverseTableMapper(TableMapper<R, L> reverseTableMapper) {
342 this.reverseTableMapper = reverseTableMapper;
343 }
344
345 protected static <M extends BaseModel<M>, S extends BaseModel<S>> int
346 deleteTableMappings(
347 BasePersistence<M> masterBasePersistence,
348 BasePersistence<S> slaveBasePersistence,
349 PortalCache<Long, long[]> masterToSlavePortalCache,
350 PortalCache<Long, long[]> slaveToMasterPortalCache,
351 MappingSqlQuery<Long> mappingSqlQuery, SqlUpdate deleteSqlUpdate,
352 long companyId, long masterPrimaryKey) {
353
354 ModelListener<M>[] masterModelListeners =
355 masterBasePersistence.getListeners();
356 ModelListener<S>[] slaveModelListeners =
357 slaveBasePersistence.getListeners();
358
359 long[] slavePrimaryKeys = getPrimaryKeys(
360 masterToSlavePortalCache, mappingSqlQuery, companyId,
361 masterPrimaryKey, false);
362
363 Class<M> masterModelClass = null;
364 Class<S> slaveModelClass = null;
365
366 if ((masterModelListeners.length > 0) ||
367 (slaveModelListeners.length > 0)) {
368
369 masterModelClass = masterBasePersistence.getModelClass();
370 slaveModelClass = slaveBasePersistence.getModelClass();
371
372 for (long slavePrimaryKey : slavePrimaryKeys) {
373 for (ModelListener<M> masterModelListener :
374 masterModelListeners) {
375
376 masterModelListener.onBeforeRemoveAssociation(
377 masterPrimaryKey, slaveModelClass.getName(),
378 slavePrimaryKey);
379 }
380
381 for (ModelListener<S> slaveModelListener :
382 slaveModelListeners) {
383
384 slaveModelListener.onBeforeRemoveAssociation(
385 slavePrimaryKey, masterModelClass.getName(),
386 masterPrimaryKey);
387 }
388 }
389 }
390
391 masterToSlavePortalCache.remove(masterPrimaryKey);
392
393 for (long slavePrimaryKey : slavePrimaryKeys) {
394 slaveToMasterPortalCache.remove(slavePrimaryKey);
395 }
396
397 int rowCount = 0;
398
399 try {
400 rowCount = deleteSqlUpdate.update(companyId, masterPrimaryKey);
401 }
402 catch (Exception e) {
403 throw new SystemException(e);
404 }
405
406 if ((masterModelListeners.length > 0) ||
407 (slaveModelListeners.length > 0)) {
408
409 for (long slavePrimaryKey : slavePrimaryKeys) {
410 for (ModelListener<M> masterModelListener :
411 masterModelListeners) {
412
413 masterModelListener.onAfterRemoveAssociation(
414 masterPrimaryKey, slaveModelClass.getName(),
415 slavePrimaryKey);
416 }
417
418 for (ModelListener<S> slaveModelListener :
419 slaveModelListeners) {
420
421 slaveModelListener.onAfterRemoveAssociation(
422 slavePrimaryKey, masterModelClass.getName(),
423 masterPrimaryKey);
424 }
425 }
426 }
427
428 return rowCount;
429 }
430
431 protected static <T extends BaseModel<T>> List<T>
432 getBaseModels(
433 PortalCache<Long, long[]> portalCache,
434 MappingSqlQuery<Long> mappingSqlQuery, long companyId,
435 long masterPrimaryKey, BasePersistence<T> slaveBasePersistence,
436 int start, int end, OrderByComparator<T> obc) {
437
438 long[] slavePrimaryKeys = getPrimaryKeys(
439 portalCache, mappingSqlQuery, companyId, masterPrimaryKey, true);
440
441 if (slavePrimaryKeys.length == 0) {
442 return Collections.emptyList();
443 }
444
445 List<T> slaveBaseModels = new ArrayList<>(slavePrimaryKeys.length);
446
447 try {
448 for (long slavePrimaryKey : slavePrimaryKeys) {
449 slaveBaseModels.add(
450 slaveBasePersistence.findByPrimaryKey(slavePrimaryKey));
451 }
452 }
453 catch (NoSuchModelException nsme) {
454 throw new SystemException(nsme);
455 }
456
457 if (obc != null) {
458 Collections.sort(slaveBaseModels, obc);
459 }
460
461 return ListUtil.subList(slaveBaseModels, start, end);
462 }
463
464 protected static long[] getPrimaryKeys(
465 PortalCache<Long, long[]> portalCache,
466 MappingSqlQuery<Long> mappingSqlQuery, long companyId,
467 long masterPrimaryKey, boolean updateCache) {
468
469 long[] primaryKeys = portalCache.get(masterPrimaryKey);
470
471 if (primaryKeys == null) {
472 List<Long> primaryKeysList = null;
473
474 try {
475 primaryKeysList = mappingSqlQuery.execute(
476 companyId, masterPrimaryKey);
477 }
478 catch (Exception e) {
479 throw new SystemException(e);
480 }
481
482 primaryKeys = new long[primaryKeysList.size()];
483
484 for (int i = 0; i < primaryKeys.length; i++) {
485 primaryKeys[i] = primaryKeysList.get(i);
486 }
487
488 Arrays.sort(primaryKeys);
489
490 if (updateCache) {
491 PortalCacheHelperUtil.putWithoutReplicator(
492 portalCache, masterPrimaryKey, primaryKeys);
493 }
494 }
495
496 return primaryKeys;
497 }
498
499 protected boolean containsTableMapping(
500 long companyId, long leftPrimaryKey, long rightPrimaryKey,
501 boolean updateCache) {
502
503 long[] rightPrimaryKeys = getPrimaryKeys(
504 getLeftToRightPortalCache(companyId), getRightPrimaryKeysSqlQuery,
505 companyId, leftPrimaryKey, updateCache);
506
507 if (Arrays.binarySearch(rightPrimaryKeys, rightPrimaryKey) < 0) {
508 return false;
509 }
510 else {
511 return true;
512 }
513 }
514
515 protected PortalCache<Long, long[]> getLeftToRightPortalCache(
516 long companyId) {
517
518 String portalCacheName = _leftToRightPortalCacheNames.get(companyId);
519
520 if (portalCacheName == null) {
521 portalCacheName =
522 TableMapper.class.getName() + "-" + tableName +
523 "-LeftToRight-" + companyId;
524
525 _leftToRightPortalCacheNames.put(companyId, portalCacheName);
526 }
527
528 return MultiVMPoolUtil.getPortalCache(portalCacheName);
529 }
530
531 protected PortalCache<Long, long[]> getRightToLeftPortalCache(
532 long companyId) {
533
534 String portalCacheName = _rightToLeftPortalCacheNames.get(companyId);
535
536 if (portalCacheName == null) {
537 portalCacheName =
538 TableMapper.class.getName() + "-" + tableName +
539 "-RightToLeft-" + companyId;
540
541 _rightToLeftPortalCacheNames.put(companyId, portalCacheName);
542 }
543
544 return MultiVMPoolUtil.getPortalCache(portalCacheName);
545 }
546
547 protected SqlUpdate addTableMappingSqlUpdate;
548 protected String companyColumnName;
549 protected SqlUpdate deleteLeftPrimaryKeyTableMappingsSqlUpdate;
550 protected SqlUpdate deleteRightPrimaryKeyTableMappingsSqlUpdate;
551 protected SqlUpdate deleteTableMappingSqlUpdate;
552 protected MappingSqlQuery<Long> getLeftPrimaryKeysSqlQuery;
553 protected MappingSqlQuery<Long> getRightPrimaryKeysSqlQuery;
554 protected BasePersistence<L> leftBasePersistence;
555 protected String leftColumnName;
556 protected TableMapper<R, L> reverseTableMapper;
557 protected BasePersistence<R> rightBasePersistence;
558 protected String rightColumnName;
559 protected String tableName;
560
561 private final Map<Long, String> _leftToRightPortalCacheNames =
562 new ConcurrentHashMap<>();
563 private final Map<Long, String> _rightToLeftPortalCacheNames =
564 new ConcurrentHashMap<>();
565
566 }