/* * Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package li.strolch.xmlpers.api; import static li.strolch.xmlpers.util.AssertionUtil.assertIsIdRef; import static li.strolch.xmlpers.util.AssertionUtil.assertIsNotIdRef; import static li.strolch.xmlpers.util.AssertionUtil.assertIsNotRootRef; import static li.strolch.xmlpers.util.AssertionUtil.assertNotNull; import static li.strolch.xmlpers.util.AssertionUtil.assertObjectRead; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import li.strolch.utils.objectfilter.ObjectFilter; import li.strolch.xmlpers.objref.ObjectRef; import li.strolch.xmlpers.objref.SubTypeRef; import li.strolch.xmlpers.objref.TypeRef; /** * @author Robert von Burg <eitch@eitchnet.ch> * */ public class ObjectDao { private final ObjectFilter objectFilter; private final FileDao fileDao; private final PersistenceTransaction tx; private PersistenceContextFactoryDelegator ctxFactoryDelegator; public ObjectDao(PersistenceTransaction tx, FileDao fileDao, ObjectFilter objectFilter) { this.tx = tx; this.fileDao = fileDao; this.objectFilter = objectFilter; this.ctxFactoryDelegator = this.tx.getRealm().getCtxFactoryDelegator(); } public <T> void add(T object) { assertNotClosed(); assertNotNull(object); PersistenceContext<T> ctx = createCtx(object); ctx.getObjectRef().lock(); this.objectFilter.add(ctx.getObjectRef().getType(), ctx); } public <T> void addAll(List<T> objects) { assertNotClosed(); assertNotNull(objects); if (!objects.isEmpty()) { for (T object : objects) { PersistenceContext<T> ctx = createCtx(object); ctx.getObjectRef().lock(); this.objectFilter.add(ctx.getObjectRef().getType(), ctx); } } } public <T> void update(T object) { assertNotClosed(); assertNotNull(object); PersistenceContext<T> ctx = createCtx(object); ctx.getObjectRef().lock(); this.objectFilter.update(ctx.getObjectRef().getType(), ctx); } public <T> void updateAll(List<T> objects) { assertNotClosed(); assertNotNull(objects); if (!objects.isEmpty()) { for (T object : objects) { PersistenceContext<T> ctx = createCtx(object); ctx.getObjectRef().lock(); this.objectFilter.update(ctx.getObjectRef().getType(), ctx); } } } public <T> void remove(T object) { assertNotClosed(); assertNotNull(object); PersistenceContext<T> ctx = createCtx(object); ctx.getObjectRef().lock(); this.objectFilter.remove(ctx.getObjectRef().getType(), ctx); } public <T> void removeAll(List<T> objects) { assertNotClosed(); assertNotNull(objects); if (!objects.isEmpty()) { for (T object : objects) { PersistenceContext<T> ctx = createCtx(object); ctx.getObjectRef().lock(); this.objectFilter.remove(ctx.getObjectRef().getType(), ctx); } } } public <T> long removeAllBy(TypeRef typeRef) { assertNotClosed(); long removed = 0; Set<ObjectRef> refs = new HashSet<>(); typeRef.lock(); refs.add(typeRef); try { Set<String> types = this.tx.getMetadataDao().queryTypeSet(typeRef); for (String type : types) { ObjectRef childTypeRef = typeRef.getChildTypeRef(this.tx, type); childTypeRef.lock(); refs.add(childTypeRef); Set<String> ids = queryKeySet(childTypeRef); for (String id : ids) { ObjectRef idRef = childTypeRef.getChildIdRef(this.tx, id); PersistenceContext<T> ctx = createCtx(idRef); ctx.getObjectRef().lock(); this.objectFilter.remove(ctx.getObjectRef().getType(), ctx); removed++; } } } finally { for (ObjectRef ref : refs) { ref.unlock(); } } return removed; } public <T> long removeAllBy(SubTypeRef subTypeRef) { assertNotClosed(); assertIsNotRootRef(subTypeRef); assertIsNotIdRef(subTypeRef); long removed = 0; subTypeRef.lock(); try { Set<String> ids = queryKeySet(subTypeRef); for (String id : ids) { ObjectRef idRef = subTypeRef.getChildIdRef(this.tx, id); PersistenceContext<T> ctx = createCtx(idRef); ctx.getObjectRef().lock(); this.objectFilter.remove(ctx.getObjectRef().getType(), ctx); removed++; } } finally { subTypeRef.unlock(); } return removed; } public <T> void removeById(ObjectRef objectRef) { assertNotClosed(); assertIsIdRef(objectRef); PersistenceContext<T> ctx = createCtx(objectRef); ctx.getObjectRef().lock(); this.objectFilter.remove(objectRef.getType(), ctx); } public <T> void removeAll(ObjectRef parentRef) { assertNotClosed(); assertIsNotIdRef(parentRef); assertIsNotRootRef(parentRef); parentRef.lock(); try { Set<String> keySet = queryKeySet(parentRef); for (String id : keySet) { ObjectRef childRef = parentRef.getChildIdRef(this.tx, id); PersistenceContext<T> ctx = createCtx(childRef); ctx.getObjectRef().lock(); this.objectFilter.remove(childRef.getType(), ctx); } } finally { parentRef.unlock(); } } public <T> boolean hasElement(ObjectRef objectRef) { assertNotClosed(); assertIsIdRef(objectRef); objectRef.lock(); try { PersistenceContext<T> ctx = objectRef.<T> createPersistenceContext(this.tx); return this.fileDao.exists(ctx); } finally { objectRef.unlock(); } } public <T> T queryById(ObjectRef objectRef) { assertNotClosed(); assertIsIdRef(objectRef); objectRef.lock(); try { PersistenceContext<T> ctx = objectRef.<T> createPersistenceContext(this.tx); this.fileDao.performRead(ctx); return ctx.getObject(); } finally { objectRef.unlock(); } } public <T> List<T> queryAll(ObjectRef parentRef) { assertNotClosed(); assertIsNotIdRef(parentRef); parentRef.lock(); try { MetadataDao metadataDao = this.tx.getMetadataDao(); Set<String> keySet = metadataDao.queryKeySet(parentRef); List<T> result = new ArrayList<>(); for (String id : keySet) { ObjectRef childRef = parentRef.getChildIdRef(this.tx, id); PersistenceContext<T> childCtx = childRef.createPersistenceContext(this.tx); childCtx.getObjectRef().lock(); try { this.fileDao.performRead(childCtx); assertObjectRead(childCtx); result.add(childCtx.getObject()); } finally { childCtx.getObjectRef().unlock(); } } return result; } finally { parentRef.unlock(); } } public Set<String> queryKeySet(ObjectRef parentRef) { assertNotClosed(); assertIsNotIdRef(parentRef); parentRef.lock(); try { MetadataDao metadataDao = this.tx.getMetadataDao(); Set<String> keySet = metadataDao.queryKeySet(parentRef); return keySet; } finally { parentRef.unlock(); } } public long querySize(ObjectRef parentRef) { assertNotClosed(); assertIsNotIdRef(parentRef); parentRef.lock(); try { MetadataDao metadataDao = this.tx.getMetadataDao(); long size = metadataDao.querySize(parentRef); return size; } finally { parentRef.unlock(); } } public <T> PersistenceContext<T> createCtx(T object) { return this.ctxFactoryDelegator.<T> getCtxFactory(object.getClass()).createCtx(this.tx.getObjectRefCache(), object); } public <T> PersistenceContext<T> createCtx(ObjectRef objectRef) { String type = objectRef.getType(); PersistenceContextFactory<T> ctxFactory = this.ctxFactoryDelegator.<T> getCtxFactory(type); return ctxFactory.createCtx(objectRef); } private void assertNotClosed() { if (!this.tx.isOpen()) throw new IllegalStateException("Transaction has been closed and thus no operation can be performed!"); //$NON-NLS-1$ } }