Java tutorial
/* * Copyright 2006 Open Source Applications Foundation * * 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 org.unitedinternet.cosmo.dao.hibernate; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.validation.ConstraintViolationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.FlushMode; import org.hibernate.Hibernate; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.ObjectDeletedException; import org.hibernate.ObjectNotFoundException; import org.hibernate.Query; import org.hibernate.StatelessSession; import org.hibernate.UnresolvableObjectException; import org.hibernate.cfg.AvailableSettings; import org.springframework.orm.hibernate5.SessionFactoryUtils; import org.springframework.security.core.token.TokenService; import org.unitedinternet.cosmo.CosmoException; import org.unitedinternet.cosmo.dao.DuplicateItemNameException; import org.unitedinternet.cosmo.dao.ItemDao; import org.unitedinternet.cosmo.dao.ItemNotFoundException; import org.unitedinternet.cosmo.dao.ModelValidationException; import org.unitedinternet.cosmo.dao.query.ItemFilterProcessor; import org.unitedinternet.cosmo.dao.query.ItemPathTranslator; import org.unitedinternet.cosmo.model.CollectionItem; import org.unitedinternet.cosmo.model.EventStamp; import org.unitedinternet.cosmo.model.HomeCollectionItem; import org.unitedinternet.cosmo.model.ICalendarItem; import org.unitedinternet.cosmo.model.Item; import org.unitedinternet.cosmo.model.Stamp; import org.unitedinternet.cosmo.model.Ticket; import org.unitedinternet.cosmo.model.UidInUseException; import org.unitedinternet.cosmo.model.User; import org.unitedinternet.cosmo.model.filter.ItemFilter; import org.unitedinternet.cosmo.model.hibernate.BaseModelObject; import org.unitedinternet.cosmo.model.hibernate.HibCollectionItem; import org.unitedinternet.cosmo.model.hibernate.HibEventStamp; import org.unitedinternet.cosmo.model.hibernate.HibHomeCollectionItem; import org.unitedinternet.cosmo.model.hibernate.HibItem; import org.unitedinternet.cosmo.model.hibernate.HibItemTombstone; import org.unitedinternet.cosmo.util.VersionFourGenerator; /** * Implementation of ItemDao using Hibernate persistent objects. */ public abstract class ItemDaoImpl extends AbstractDaoImpl implements ItemDao { private static final Log LOG = LogFactory.getLog(ItemDaoImpl.class); private VersionFourGenerator idGenerator = null; private TokenService ticketKeyGenerator = null; private ItemPathTranslator itemPathTranslator = null; private ItemFilterProcessor itemFilterProcessor = null; /* * (non-Javadoc) * * @see org.unitedinternet.cosmo.dao.ItemDao#findItemByPath(java.lang.String) */ public Item findItemByPath(String path) { try { Item dbItem = itemPathTranslator.findItemByPath(path); return dbItem; } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /* (non-Javadoc) * @see org.unitedinternet.cosmo.dao.ItemDao#findItemByPath(java.lang.String, java.lang.String) */ public Item findItemByPath(String path, String parentUid) { try { Item parent = findItemByUid(parentUid); if (parent == null) { return null; } Item item = itemPathTranslator.findItemByPath(path, (CollectionItem) parent); return item; } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /* (non-Javadoc) * @see org.unitedinternet.cosmo.dao.ItemDao#findItemParentByPath(java.lang.String) */ public Item findItemParentByPath(String path) { try { Item dbItem = itemPathTranslator.findItemParent(path); return dbItem; } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /* * (non-Javadoc) * * @see org.unitedinternet.cosmo.dao.ItemDao#findEventStampFromDbByUid(java.lang.String) */ @SuppressWarnings("unchecked") public <STAMP_TYPE extends Stamp> STAMP_TYPE findStampByInternalItemUid(String internalItemUid, Class<STAMP_TYPE> clazz) { try (StatelessSession session = this.openStatelessSession()) { List<Stamp> stamps = (List<Stamp>) session.createNamedQuery("item.stamps.by.uid") .setParameter("uid", internalItemUid) .setHint(AvailableSettings.JPA_SHARED_CACHE_STORE_MODE, null) .setHint(AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE, null).getResultList(); for (Stamp stamp : stamps) { if (clazz.isInstance(stamp)) { return clazz.cast(stamp); } } } catch (HibernateException e) { throw SessionFactoryUtils.convertHibernateAccessException(e); } return null; } /* * (non-Javadoc) * * @see org.unitedinternet.cosmo.dao.ItemDao#findItemByUid(java.lang.String) */ public Item findItemByUid(String uid) { try { // prevent auto flushing when looking up item by uid getSession().setFlushMode(FlushMode.MANUAL); return (Item) getSession().byNaturalId(HibItem.class).using("uid", uid).load(); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /* * (non-Javadoc) * * @see org.unitedinternet.cosmo.dao.ItemDao#removeItem(org.unitedinternet.cosmo.model.Item) */ public void removeItem(Item item) { try { if (item == null) { throw new IllegalArgumentException("item cannot be null"); } if (item instanceof HomeCollectionItem) { throw new IllegalArgumentException("cannot remove root item"); } removeItemInternal(item); getSession().flush(); } catch (ObjectNotFoundException onfe) { throw new ItemNotFoundException("item not found"); } catch (ObjectDeletedException ode) { throw new ItemNotFoundException("item not found"); } catch (UnresolvableObjectException uoe) { throw new ItemNotFoundException("item not found"); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } public HomeCollectionItem getRootItem(User user, boolean forceReload) { if (forceReload) { getSession().clear(); } return getRootItem(user); } /* * (non-Javadoc) * * @see org.unitedinternet.cosmo.dao.ItemDao#getRootItem(org.unitedinternet.cosmo.model.User) */ public HomeCollectionItem getRootItem(User user) { try { return findRootItem(getBaseModelObject(user).getId()); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /* (non-Javadoc) * @see org.unitedinternet.cosmo.dao.ItemDao#createRootItem(org.unitedinternet.cosmo.model.User) */ public HomeCollectionItem createRootItem(User user) { try { if (user == null) { throw new IllegalArgumentException("invalid user"); } if (findRootItem(getBaseModelObject(user).getId()) != null) { throw new CosmoException("user already has root item", new CosmoException()); } HomeCollectionItem newItem = new HibHomeCollectionItem(); newItem.setOwner(user); newItem.setName(user.getUsername()); //do not set this, it might be sensitive or different than name //newItem.setDisplayName(newItem.getName()); setBaseItemProps(newItem); getSession().save(newItem); getSession().flush(); return newItem; } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } catch (ConstraintViolationException cve) { logConstraintViolationException(cve); throw cve; } } public void addItemToCollection(Item item, CollectionItem collection) { try { addItemToCollectionInternal(item, collection); getSession().flush(); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } public void removeItemFromCollection(Item item, CollectionItem collection) { try { removeItemFromCollectionInternal(item, collection); getSession().flush(); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } public Set<Ticket> getTickets(Item item) { if (item == null) { throw new IllegalArgumentException("item cannot be null"); } try { getSession().refresh(item); return item.getTickets(); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } public Ticket findTicket(String key) { if (key == null) { throw new IllegalArgumentException("key cannot be null"); } try { // prevent auto flushing when looking up ticket getSession().setFlushMode(FlushMode.MANUAL); Query hibQuery = getSession().getNamedQuery("ticket.by.key").setParameter("key", key); hibQuery.setCacheable(true); hibQuery.setFlushMode(FlushMode.MANUAL); return (Ticket) hibQuery.uniqueResult(); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } public void createTicket(Item item, Ticket ticket) { try { if (ticket == null) { throw new IllegalArgumentException("ticket cannot be null"); } if (item == null) { throw new IllegalArgumentException("item cannot be null"); } User owner = ticket.getOwner(); if (owner == null) { throw new IllegalArgumentException("ticket must have owner"); } if (ticket.getKey() == null) { ticket.setKey(ticketKeyGenerator.allocateToken("").getKey()); } ticket.setCreated(new Date()); getSession().update(item); item.addTicket(ticket); getSession().flush(); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } catch (ConstraintViolationException cve) { logConstraintViolationException(cve); throw cve; } } public Ticket getTicket(Item item, String key) { try { getSession().refresh(item); return getTicketRecursive(item, key); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } public void removeTicket(Item item, Ticket ticket) { try { getSession().update(item); item.removeTicket(ticket); getSession().flush(); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /* (non-Javadoc) * @see org.unitedinternet.cosmo.dao.ItemDao#removeItemByPath(java.lang.String) */ public void removeItemByPath(String path) { try { Item item = itemPathTranslator.findItemByPath(path); if (item == null) { throw new ItemNotFoundException("item at " + path + " not found"); } removeItem(item); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /* (non-Javadoc) * @see org.unitedinternet.cosmo.dao.ItemDao#removeItemByUid(java.lang.String) */ public void removeItemByUid(String uid) { try { Item item = findItemByUid(uid); if (item == null) { throw new ItemNotFoundException("item with uid " + uid + " not found"); } removeItem(item); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } public void copyItem(Item item, String destPath, boolean deepCopy) { try { String copyName = itemPathTranslator.getItemName(destPath); if (copyName == null || "".equals(copyName)) { throw new IllegalArgumentException("path must include name"); } if (item instanceof HomeCollectionItem) { throw new IllegalArgumentException("cannot copy root collection"); } CollectionItem newParent = (CollectionItem) itemPathTranslator.findItemParent(destPath); if (newParent == null) { throw new ItemNotFoundException("parent collection not found"); } verifyNotInLoop(item, newParent); Item newItem = copyItemInternal(item, newParent, deepCopy); newItem.setName(copyName); getSession().flush(); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } catch (ConstraintViolationException cve) { logConstraintViolationException(cve); throw cve; } } /* (non-Javadoc) * @see org.unitedinternet.cosmo.dao.ItemDao#moveItem(java.lang.String, java.lang.String) */ public void moveItem(String fromPath, String toPath) { try { // Get current item Item item = itemPathTranslator.findItemByPath(fromPath); if (item == null) { throw new ItemNotFoundException("item " + fromPath + " not found"); } if (item instanceof HomeCollectionItem) { throw new IllegalArgumentException("cannot move root collection"); } // Name of moved item String moveName = itemPathTranslator.getItemName(toPath); if (moveName == null || "".equals(moveName)) { throw new IllegalArgumentException("path must include name"); } // Parent of moved item CollectionItem parent = (CollectionItem) itemPathTranslator.findItemParent(toPath); if (parent == null) { throw new ItemNotFoundException("parent collecion not found"); } // Current parent CollectionItem oldParent = (CollectionItem) itemPathTranslator.findItemParent(fromPath); verifyNotInLoop(item, parent); item.setName(moveName); if (!parent.getUid().equals(oldParent.getUid())) { ((HibCollectionItem) parent).removeTombstone(item); // Copy over existing CollectionItemDetails ((HibItem) item).addParent(parent); // Remove item from old parent collection getHibItem(oldParent).addTombstone(new HibItemTombstone(oldParent, item)); ((HibItem) item).removeParent(oldParent); } getSession().flush(); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } catch (ConstraintViolationException cve) { logConstraintViolationException(cve); throw cve; } } /* (non-Javadoc) * @see org.unitedinternet.cosmo.dao.ItemDao#refreshItem(org.unitedinternet.cosmo.model.Item) */ public void refreshItem(Item item) { try { getSession().refresh(item); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /* (non-Javadoc) * @see org.unitedinternet.cosmo.dao.ItemDao#initializeItem(org.unitedinternet.cosmo.model.Item) */ public void initializeItem(Item item) { try { LOG.info("initialize Item : " + item.getUid()); // initialize all the proxied-associations, to prevent // lazy-loading of this data Hibernate.initialize(item.getAttributes()); Hibernate.initialize(item.getStamps()); Hibernate.initialize(item.getTombstones()); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /** * find the set of collection items as children of the given collection item. * * @param collectionItem parent collection item * @return set of children collection items or empty list of parent collection has no children */ public Set<CollectionItem> findCollectionItems(CollectionItem collectionItem) { try { HashSet<CollectionItem> children = new HashSet<CollectionItem>(); Query hibQuery = getSession().getNamedQuery("collections.children.by.parent").setParameter("parent", collectionItem); List<?> results = hibQuery.list(); for (Iterator<?> it = results.iterator(); it.hasNext();) { CollectionItem content = (CollectionItem) it.next(); children.add(content); } return children; } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /** * Find a set of items using an ItemFilter. * * @param filter criteria to filter items by * @return set of items matching ItemFilter */ public Set<Item> findItems(ItemFilter filter) { try { return itemFilterProcessor.processFilter(filter); } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /** * Find a set of items using a set of ItemFilters. The set of items * returned includes all items that match any of the filters. * * @param filters criteria to filter items by * @return set of items matching any of the filters */ public Set<Item> findItems(ItemFilter[] filters) { try { HashSet<Item> returnSet = new HashSet<Item>(); for (ItemFilter filter : filters) { returnSet.addAll(itemFilterProcessor.processFilter(filter)); } return returnSet; } catch (HibernateException e) { getSession().clear(); throw SessionFactoryUtils.convertHibernateAccessException(e); } } /** * Generates a unique ID. Provided for consumers that need to * manipulate an item's UID before creating the item. */ public String generateUid() { return idGenerator.nextStringIdentifier(); } /** * Set the unique ID generator for new items * * @param idGenerator */ public void setIdGenerator(VersionFourGenerator idGenerator) { this.idGenerator = idGenerator; } public VersionFourGenerator getIdGenerator() { return idGenerator; } /** * Set the unique key generator for new tickets * * @param ticketKeyGenerator */ public void setTicketKeyGenerator(TokenService ticketKeyGenerator) { this.ticketKeyGenerator = ticketKeyGenerator; } public TokenService getTicketKeyGenerator() { return ticketKeyGenerator; } public ItemPathTranslator getItemPathTranslator() { return itemPathTranslator; } /** * Set the path translator. The path translator is responsible for * translating a path to an item in the database. * * @param itemPathTranslator */ public void setItemPathTranslator(ItemPathTranslator itemPathTranslator) { this.itemPathTranslator = itemPathTranslator; } public ItemFilterProcessor getItemFilterProcessor() { return itemFilterProcessor; } public void setItemFilterProcessor(ItemFilterProcessor itemFilterProcessor) { this.itemFilterProcessor = itemFilterProcessor; } /* * (non-Javadoc) * * @see org.unitedinternet.cosmo.dao.Dao#destroy() */ public abstract void destroy(); /* * (non-Javadoc) * * @see org.unitedinternet.cosmo.dao.Dao#init() */ public void init() { if (idGenerator == null) { throw new IllegalStateException("idGenerator is required"); } if (ticketKeyGenerator == null) { throw new IllegalStateException("ticketKeyGenerator is required"); } if (itemPathTranslator == null) { throw new IllegalStateException("itemPathTranslator is required"); } if (itemFilterProcessor == null) { throw new IllegalStateException("itemFilterProcessor is required"); } } protected Item copyItemInternal(Item item, CollectionItem newParent, boolean deepCopy) { Item item2 = item.copy(); item2.setName(item.getName()); // copy base Item fields setBaseItemProps(item2); ((HibItem) item2).addParent(newParent); // save Item before attempting deep copy getSession().save(item2); getSession().flush(); // copy children if collection and deepCopy = true if (deepCopy == true && item instanceof CollectionItem) { CollectionItem collection = (CollectionItem) item; for (Item child : collection.getChildren()) { copyItemInternal(child, (CollectionItem) item2, true); } } return item2; } /** * Checks to see if a parent Item is currently a child of a target item. If * so, then this would put the hierarchy into a loop and is not allowed. * * @param item * @param newParent * @throws org.unitedinternet.cosmo.dao.ModelValidationException if newParent is child of item */ protected void verifyNotInLoop(Item item, CollectionItem newParent) { // need to verify that the new parent is not a child // of the item, otherwise we get a loop if (getBaseModelObject(item).getId().equals(getBaseModelObject(newParent).getId())) { throw new ModelValidationException(newParent, "Invalid parent - will cause loop"); } // If item is not a collection then all is good if (!(item instanceof CollectionItem)) { return; } CollectionItem collection = (CollectionItem) item; getSession().refresh(collection); for (Item nextItem : collection.getChildren()) { verifyNotInLoop(nextItem, newParent); } } /** * Verifies that name is unique in collection, meaning no item exists * in collection with the same item name. * * @param item item name to check * @param collection collection to check against * @throws org.unitedinternet.cosmo.dao.DuplicateItemNameException if item with same name exists * in collection */ protected void verifyItemNameUnique(Item item, CollectionItem collection) { Query hibQuery = getSession().getNamedQuery("itemId.by.parentId.name"); hibQuery.setParameter("name", item.getName()).setParameter("parentid", ((HibItem) collection).getId()); List<Long> results = hibQuery.list(); if (results.size() > 0) { throw new DuplicateItemNameException(item, "item name " + item.getName() + " already exists in collection " + collection.getUid()); } } /** * Find the DbItem with the specified dbId * * @param dbId dbId of DbItem to find * @return DbItem with specified dbId */ protected Item findItemByDbId(Long dbId) { return (Item) getSession().get(Item.class, dbId); } // Set server generated item properties protected void setBaseItemProps(Item item) { if (item.getUid() == null) { item.setUid(idGenerator.nextStringIdentifier()); } if (item.getName() == null) { item.setName(item.getUid()); } if (item instanceof ICalendarItem) { ICalendarItem ical = (ICalendarItem) item; if (ical.getIcalUid() == null) { ical.setIcalUid(item.getUid()); EventStamp es = HibEventStamp.getStamp(ical); if (es != null) { es.setIcalUid(ical.getIcalUid()); } } } for (Ticket ticket : item.getTickets()) { if (ticket.getOwner() == null) { ticket.setOwner(item.getOwner()); } if (ticket.getKey() == null) { ticket.setKey(ticketKeyGenerator.allocateToken("").getKey()); } if (ticket.getTimeout() == null) { ticket.setTimeout(Ticket.TIMEOUT_INFINITE); } ticket.setCreated(new Date()); } } protected Item findItemByParentAndName(Long userDbId, Long parentDbId, String name) { Query hibQuery = null; if (parentDbId != null) { hibQuery = getSession().getNamedQuery("item.by.ownerId.parentId.name").setParameter("ownerid", userDbId) .setParameter("parentid", parentDbId).setParameter("name", name); } else { hibQuery = getSession().getNamedQuery("item.by.ownerId.nullParent.name") .setParameter("ownerid", userDbId).setParameter("name", name); } hibQuery.setFlushMode(FlushMode.MANUAL); return (Item) hibQuery.uniqueResult(); } protected Item findItemByParentAndNameMinusItem(Long userDbId, Long parentDbId, String name, Long itemId) { Query hibQuery = null; if (parentDbId != null) { hibQuery = getSession().getNamedQuery("item.by.ownerId.parentId.name.minusItem") .setParameter("itemid", itemId).setParameter("ownerid", userDbId) .setParameter("parentid", parentDbId).setParameter("name", name); } else { hibQuery = getSession().getNamedQuery("item.by.ownerId.nullParent.name.minusItem") .setParameter("itemid", itemId).setParameter("ownerid", userDbId).setParameter("name", name); } hibQuery.setFlushMode(FlushMode.MANUAL); return (Item) hibQuery.uniqueResult(); } protected HomeCollectionItem findRootItem(Long dbUserId) { Query hibQuery = getSession().getNamedQuery("homeCollection.by.ownerId").setParameter("ownerid", dbUserId); hibQuery.setCacheable(true); hibQuery.setFlushMode(FlushMode.MANUAL); return (HomeCollectionItem) hibQuery.uniqueResult(); } protected void checkForDuplicateUid(Item item) { // verify uid not in use if (item.getUid() != null) { // Lookup item by uid Query hibQuery = getSession().getNamedQuery("itemid.by.uid").setParameter("uid", item.getUid()); hibQuery.setFlushMode(FlushMode.MANUAL); Long itemId = (Long) hibQuery.uniqueResult(); // if uid is in use throw exception if (itemId != null) { throw new UidInUseException(item.getUid(), "uid " + item.getUid() + " already in use"); } } } protected Ticket getTicketRecursive(Item item, String key) { if (item == null) { return null; } for (Ticket ticket : item.getTickets()) { if (ticket.getKey().equals(key)) { return ticket; } } for (Item parent : item.getParents()) { Ticket ticket = getTicketRecursive(parent, key); if (ticket != null) { return ticket; } } return null; } protected void attachToSession(Item item) { if (getSession().contains(item)) { return; } getSession().lock(item, LockMode.NONE); } protected void removeItemFromCollectionInternal(Item item, CollectionItem collection) { getSession().update(collection); getSession().update(item); // do nothing if item doesn't belong to collection if (!item.getParents().contains(collection)) { return; } getHibItem(collection).addTombstone(new HibItemTombstone(collection, item)); ((HibItem) item).removeParent(collection); // If the item belongs to no collection, then it should // be purged. if (item.getParents().size() == 0) { removeItemInternal(item); } } protected void addItemToCollectionInternal(Item item, CollectionItem collection) { verifyItemNameUnique(item, collection); getSession().update(item); getSession().update(collection); ((HibCollectionItem) collection).removeTombstone(item); ((HibItem) item).addParent(collection); } protected void removeItemInternal(Item item) { getSession().delete(item); } protected BaseModelObject getBaseModelObject(Object obj) { return (BaseModelObject) obj; } protected HibItem getHibItem(Item item) { return (HibItem) item; } protected HibCollectionItem getHibCollectionItem(CollectionItem item) { return (HibCollectionItem) item; } }