Java tutorial
/******************************************************************************* * Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved. * * This file is part of the OpenWGA server platform. * * OpenWGA is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * In addition, a special exception is granted by the copyright holders * of OpenWGA called "OpenWGA plugin exception". You should have received * a copy of this exception along with OpenWGA in file COPYING. * If not, see <http://www.openwga.com/gpl-plugin-exception>. * * OpenWGA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenWGA in file COPYING. * If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package de.innovationgate.webgate.api.jdbc; import java.io.File; import java.io.InputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.management.MXBean; import javax.management.ObjectName; import org.apache.commons.collections.Bag; import org.apache.commons.collections.bag.HashBag; import org.apache.commons.collections.map.LinkedMap; import org.apache.log4j.Logger; import org.hibernate.CacheMode; import org.hibernate.Criteria; import org.hibernate.FlushMode; import org.hibernate.Hibernate; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.MappingException; import org.hibernate.ObjectDeletedException; import org.hibernate.ObjectNotFoundException; import org.hibernate.Query; import org.hibernate.QueryException; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.Session.LockRequest; import org.hibernate.SessionBuilder; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.UnresolvableObjectException; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.criterion.Restrictions; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.ColumnNameCache; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.exception.SQLGrammarException; import org.hibernate.id.UUIDHexGenerator; import org.hibernate.id.enhanced.TableGenerator; import org.hibernate.jdbc.ReturningWork; import org.hibernate.jdbc.Work; import org.hibernate.mapping.SimpleValue; import org.hibernate.service.ServiceRegistryBuilder; import org.hibernate.service.jdbc.connections.spi.ConnectionProvider; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.Stoppable; import org.hibernate.stat.Statistics; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.Dom4JDriver; import de.innovationgate.monitoring.JmxManager; import de.innovationgate.utils.TemporaryFile; import de.innovationgate.utils.WGUtils; import de.innovationgate.webgate.api.MetaInfo; import de.innovationgate.webgate.api.WGACLCore; import de.innovationgate.webgate.api.WGAPIException; import de.innovationgate.webgate.api.WGArea; import de.innovationgate.webgate.api.WGAuthorisationException; import de.innovationgate.webgate.api.WGBackendException; import de.innovationgate.webgate.api.WGClosedSessionException; import de.innovationgate.webgate.api.WGColumnSet; import de.innovationgate.webgate.api.WGContent; import de.innovationgate.webgate.api.WGContentKey; import de.innovationgate.webgate.api.WGContentType; import de.innovationgate.webgate.api.WGCreationException; import de.innovationgate.webgate.api.WGDatabase; import de.innovationgate.webgate.api.WGDatabaseCore; import de.innovationgate.webgate.api.WGDatabaseCoreFeaturePageSequences; import de.innovationgate.webgate.api.WGDatabaseCoreFeatureReturnHierarchyCount; import de.innovationgate.webgate.api.WGDatabaseCoreFeatureSequenceProvider; import de.innovationgate.webgate.api.WGDatabaseRevision; import de.innovationgate.webgate.api.WGDocument; import de.innovationgate.webgate.api.WGDocumentCore; import de.innovationgate.webgate.api.WGDocumentKey; import de.innovationgate.webgate.api.WGFactory; import de.innovationgate.webgate.api.WGFileMetaData; import de.innovationgate.webgate.api.WGIllegalArgumentException; import de.innovationgate.webgate.api.WGIllegalDataException; import de.innovationgate.webgate.api.WGInvalidDatabaseException; import de.innovationgate.webgate.api.WGLanguage; import de.innovationgate.webgate.api.WGNotSupportedException; import de.innovationgate.webgate.api.WGPageOrderSet; import de.innovationgate.webgate.api.WGPersonalisationDatabaseCore; import de.innovationgate.webgate.api.WGProcedureException; import de.innovationgate.webgate.api.WGQueryException; import de.innovationgate.webgate.api.WGRelationData; import de.innovationgate.webgate.api.WGResultSetCore; import de.innovationgate.webgate.api.WGSessionContext; import de.innovationgate.webgate.api.WGStructEntry; import de.innovationgate.webgate.api.WGSystemException; import de.innovationgate.webgate.api.WGUnavailableException; import de.innovationgate.webgate.api.WGUpdateLog; import de.innovationgate.webgate.api.WGUserAccess; import de.innovationgate.webgate.api.WGUserDetails; import de.innovationgate.webgate.api.WGWrongRevisionException; import de.innovationgate.webgate.api.auth.AuthenticationSession; import de.innovationgate.webgate.api.auth.AuthenticationSourceListener; import de.innovationgate.webgate.api.auth.MasterLoginAuthSession; import de.innovationgate.webgate.api.jdbc.custom.JDBCConnectionException; import de.innovationgate.webgate.api.jdbc.custom.JDBCConnectionProvider; import de.innovationgate.webgate.api.jdbc.filehandling.CS3FileHandling; import de.innovationgate.webgate.api.jdbc.filehandling.CS41FileHandling; import de.innovationgate.webgate.api.jdbc.filehandling.CS5FileHandling; import de.innovationgate.webgate.api.jdbc.filehandling.CS5P4ContentFileDescriptor; import de.innovationgate.webgate.api.jdbc.filehandling.CS5P4FileHandling; import de.innovationgate.webgate.api.jdbc.filehandling.CS5P5FileHandling; import de.innovationgate.webgate.api.jdbc.filehandling.FileHandling; import de.innovationgate.webgate.api.jdbc.pool.DBCPConnectionProvider; import de.innovationgate.webgate.api.jdbc.pool.DBCPReplicationConnectionProvider; import de.innovationgate.webgate.api.mysql.GaleraClusterTableGenerator; import de.innovationgate.webgate.api.mysql.MySqlDatabaseServer; import de.innovationgate.webgate.api.servers.WGDatabaseServer; import de.innovationgate.webgate.api.utils.MasterSessionTask; import de.innovationgate.wga.common.Constants; import de.innovationgate.wga.config.Database; import de.innovationgate.wga.config.DatabaseServer; public class WGDatabaseImpl implements WGDatabaseCore, WGPersonalisationDatabaseCore, WGDatabaseCoreFeatureReturnHierarchyCount, WGDatabaseCoreFeatureSequenceProvider, WGDatabaseCoreFeaturePageSequences, AuthenticationSourceListener { @MXBean public interface StatisticsMXBean extends Statistics { } public static class CSVersion { private double _version; private int _patchLevel; public CSVersion(double version, int patchLevel) { _version = version; _patchLevel = patchLevel; } public double getVersion() { return _version; } public int getPatchLevel() { return _patchLevel; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + _patchLevel; long temp; temp = Double.doubleToLongBits(_version); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; CSVersion other = (CSVersion) obj; if (_patchLevel != other._patchLevel) return false; if (Double.doubleToLongBits(_version) != Double.doubleToLongBits(other._version)) return false; return true; } } public class DocumentDependencyComparator implements Comparator<WGUpdateLog> { public int compare(WGUpdateLog o1, WGUpdateLog o2) { // Different times int timeDiff = o1.getDate().compareTo(o2.getDate()); if (timeDiff != 0) { return timeDiff; } // Determine sort numbers for operations/doctypes int sortNr1 = determineSortNumber(o1); int sortNr2 = determineSortNumber(o2); return 2 - 1; } private int determineSortNumber(WGUpdateLog o) { int nr = 1; WGDocumentKey docKey = new WGDocumentKey(o.getDocumentKey()); switch (docKey.getDocType()) { case WGDocument.TYPE_CONTENT: nr = 3; break; case WGDocument.TYPE_STRUCTENTRY: nr = 2; break; } if (o.getType() == WGUpdateLog.TYPE_DELETE) { nr = nr * -1; } return nr; } } private static final String CUSTOM_SEQUENCE_NAMEPREFIX = "custom_"; private static final String HQLQUERY_PENDING_RELEASE_DOCS_CS5 = "content.status ='" + WGContent.STATUS_REVIEW + "' AND content.extensionData['" + WGDocument.EXTDATA_META_PREFIX + WGContent.META_PENDINGRELEASE.toLowerCase() + "'].boolean = 1"; private static final String HQLQUERY_PENDING_RELEASE_DOCS_CS3 = "content.status ='" + WGContent.STATUS_REVIEW + "' AND content.items['" + WGContent.ITEM_PENDINGRELEASE.toLowerCase() + "'].number = 1"; private static final String HQLQUERY_GET_STRUCT_BY_NAME = "from StructEntry as struct where struct.uniquename=:name"; public static final String HQL_FETCHTYPE_LAZY = "lazy"; public static final String HQL_FETCHTYPE_STRAIGHT = "straight"; private static final String HQLQUERY_LAZY_PARENTCHECK = "select new de.innovationgate.webgate.api.WGContentQueryResult(content.structentry.key, content.language.name, content.version, parent.key, area.name) " + "from Content as content " + "left outer join content.structentry.parententry as parent " + "left outer join content.structentry.area as area " + "where "; private static final String HQLQUERY_LAZY = "select new de.innovationgate.webgate.api.WGContentKey(content.structentry.key, content.language.name, content.version) from Content as content where "; // enable loadbalancing feature public static final String COPTION_LOADBALANCE = "loadbalance"; // when loadbalancing is enabled - how long should the updating user stay on // the master after the session is closed public static final String COPTION_MASTERPERSISTENCE_TIMEOUT = "masterPersistenceTimeout"; /** * Object of type {@link HotPatch} to perform a DDL hotpatch */ public static final String COPTION_HOTPATCH = "HotPatch"; public static final String DBTYPE = "jdbc/wgacontentstore"; public static final String HIBERNATE_V3_MAPPING_FILE = "de/innovationgate/webgate/api/jdbc/Mapping.hbm.xml"; public static final String HIBERNATE_V41_MAPPING_FILE = "de/innovationgate/webgate/api/jdbc/Mapping.optimizedFileHandling.hbm.xml"; public static final String HIBERNATE_V5_MAPPING_FILE = "de/innovationgate/webgate/api/jdbc/Mapping.v5.hbm.xml"; public static final String HIBERNATE_V5_P2_MAPPING_FILE = "de/innovationgate/webgate/api/jdbc/Mapping.v5p2.hbm.xml"; public static final String HIBERNATE_V5_P3_MAPPING_FILE = "de/innovationgate/webgate/api/jdbc/Mapping.v5p3.hbm.xml"; public static final String HIBERNATE_V5_P4_MAPPING_FILE = "de/innovationgate/webgate/api/jdbc/Mapping.v5p4.hbm.xml"; public static final String HIBERNATE_V5_P5_MAPPING_FILE = "de/innovationgate/webgate/api/jdbc/Mapping.v5p5.hbm.xml"; public static final String DBOPTION_MAPPINGFILE = "mapping.file"; public static final String DBOPTION_MAPPINGRESOURCE = "mapping.resource"; public static final String DBOPTION_HISTORYLOG_IDRANGE = "historylog.idrange"; public static final String DBOPTION_USE_GALERA_OPTIMIZATIONS = "mysql.galera"; public static final String COPTION_ANONYMOUS = "AnonymousAccessLevel"; public static final String COPTION_DISTINCTFILECONTENTS = "DistinctFileContents"; public static final String BACKENDSERVICE_UPGRADE_FILE_STORAGE = WGDatabaseImpl.class.getName() + ":UpgradeFileStorage"; private static final String HQLQUERY_STRAIGHT = "select content from Content as content where "; private static final String HQLQUERY_UPDATE_RELATIONS = "update from ContentRelation as relation set relation.target = :target where relation.targetstructentry = :structentry and relation.targetlanguage = :language"; public static final String COPTION_HQL_FETCH_TYPE = "HQLFetchType"; public static final String COPTION_HQL_LAZY_PARENTCHECK = "HQLLazyParentCheck"; public static final String DBMETA_PATCH_LEVEL = WGDatabase.EXTDATA_PATCH_LEVEL; public static final Integer CURRENT_PATCH_LEVEL = 1; protected SessionFactory _sessionFactory = null; protected SessionBuilder _sessionBuilder = null; private WGDatabase _db; private String _path; private boolean _hqlLazyByDefault = true; private ThreadLocal<SessionStatus> _sessionStatus = new ThreadLocal<SessionStatus>(); protected boolean _saveIsolationActive = false; private ACLImpl _aclImpl = new ACLImpl(this); public static final long DEFAULT_MASTERPERSISTENCE_TIMEOUT = 1000 * 10; // when loadbalancing is enabled - how long should the updating user stay on // the master after the session is closed private static long _masterPersistenceTimeout = DEFAULT_MASTERPERSISTENCE_TIMEOUT; private Map<String, DBUpdate> _dbUpdatesByUser = new ConcurrentHashMap<String, DBUpdate>(); private Map<String, TableGenerator> _generatorCache = new ConcurrentHashMap<String, TableGenerator>(); protected double _ddlVersion; /** * Chooses if the "query paging" feature of the optimized file handling * should be disabled (which it is by default) */ public static final String COPTION_OPTIMIZED_FILE_HANDLING_DISABLEQUERYPAGING = "OptimizedFileHandling.DisableQueryPaging"; protected static final String NATIVESQL_BOOLEAN_TRUE = "booleanTrue"; public static final String DEFAULT_MAXOPENPREPAREDSTATEMENTS = "-1"; public static class V5FastAccessKey { public V5FastAccessKey(int type, String id) { super(); this.type = type; this.id = id; } private int type; private String id; public int getType() { return type; } public String getId() { return id; } @Override public String toString() { return WGDocument.doctypeNumberToName(this.type) + "/" + this.id; } } public class LogConflict { private List _logs = new ArrayList(); private WGUpdateLog _listedLog = null; public WGUpdateLog getListedLog() { return _listedLog; } public void setListedLog(WGUpdateLog listedLog) { _listedLog = listedLog; } public List getLogs() { return _logs; } } public static class SessionStatus { private Session _session = null; private boolean _inSaveOperation = false; public Session getSession() { return _session; } public void setSession(Session session) { _session = session; } protected boolean isInSaveOperation() { return _inSaveOperation; } protected void setInSaveOperation(boolean inSaveOperation) { _inSaveOperation = inSaveOperation; } }; // bean to manage dbUpdatesByUser private class DBUpdate { private String _user; private Date _started; private boolean _sessionClosed; private WGSessionContext _sessionContext; public DBUpdate(WGSessionContext sessionContext) { _sessionContext = sessionContext; _user = _sessionContext.getUser(); _started = new Date(); _sessionClosed = false; } public boolean isSessionClosed() { return _sessionClosed; } public void setSessionClosed(boolean sessionClosed) { _sessionClosed = sessionClosed; } public Date getStarted() { return _started; } public String getUser() { return _user; } public boolean isInProgress() { if (!isSessionClosed()) { return true; } else if (_user.equals(WGDatabase.ANONYMOUS_USER)) { return _sessionContext == _db.getSessionContext(); } else if ((System.currentTimeMillis() - _masterPersistenceTimeout) >= _started.getTime()) { return false; } else { return true; } } }; private static Map<Integer, Class<? extends MainEntity>> _typeToObject = new HashMap<Integer, Class<? extends MainEntity>>(); private static Map<Class<? extends MainEntity>, Integer> _objectToType = new HashMap<Class<? extends MainEntity>, Integer>(); private ConnectionProvider _connProvider = null; protected CSVersion _csVersion; private FileHandling _fileHandling; private Configuration _conf; private volatile boolean _ugradeFileStorageRunning = false; private boolean _hqlLazyParentCheck = true; private JmxManager _jmxManager; static { _typeToObject.put(new Integer(WGDocument.TYPE_AREA), Area.class); _typeToObject.put(new Integer(WGDocument.TYPE_CONTENT), Content.class); _typeToObject.put(new Integer(WGDocument.TYPE_CONTENTTYPE), ContentType.class); _typeToObject.put(new Integer(WGDocument.TYPE_CSSJS), CSSJSModule.class); _typeToObject.put(new Integer(WGDocument.TYPE_FILECONTAINER), FileContainer.class); _typeToObject.put(new Integer(WGDocument.TYPE_LANGUAGE), Language.class); _typeToObject.put(new Integer(WGDocument.TYPE_STRUCTENTRY), StructEntry.class); _typeToObject.put(new Integer(WGDocument.TYPE_TML), TMLModule.class); _typeToObject.put(new Integer(WGDocument.TYPE_USERPROFILE), UserProfile.class); _objectToType.put(Area.class, new Integer(WGDocument.TYPE_AREA)); _objectToType.put(Content.class, new Integer(WGDocument.TYPE_CONTENT)); _objectToType.put(ContentType.class, new Integer(WGDocument.TYPE_CONTENTTYPE)); _objectToType.put(CSSJSModule.class, new Integer(WGDocument.TYPE_CSSJS)); _objectToType.put(FileContainer.class, new Integer(WGDocument.TYPE_FILECONTAINER)); _objectToType.put(Language.class, new Integer(WGDocument.TYPE_LANGUAGE)); _objectToType.put(StructEntry.class, new Integer(WGDocument.TYPE_STRUCTENTRY)); _objectToType.put(TMLModule.class, new Integer(WGDocument.TYPE_TML)); _objectToType.put(UserProfile.class, new Integer(WGDocument.TYPE_USERPROFILE)); } public Session getSession() throws WGAPIException { SessionStatus status = getSessionStatus(); Session session = status.getSession(); if (session != null) { return session; } else { throw new WGClosedSessionException(); } } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#close() */ public void close() throws WGAPIException { if (getSessionStatus().getSession() != null) { closeSession(); } try { if (_sessionFactory != null) { _sessionFactory.close(); _sessionFactory = null; } } catch (HibernateException e) { throw new WGBackendException("Error closing hibernate session factory", e); } if (_connProvider != null) { if (_connProvider instanceof Stoppable) { ((Stoppable) _connProvider).stop(); } _connProvider = null; } _dbUpdatesByUser.clear(); if (_jmxManager != null) { _jmxManager.unregister(); } } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#closeSession() */ public void closeSession() throws WGAPIException { try { Session session = getSessionStatus().getSession(); if (session != null) { Transaction trans = session.getTransaction(); if (trans != null && trans.isActive()) { trans.rollback(); } } } catch (Throwable e) { WGFactory.getLogger().error("Exception rolling back transaction on session close", e); } try { // set session closed flag on dbupdate if present if (_db.isSessionOpen()) { String user = _db.getSessionContext().getUser(); DBUpdate update = (DBUpdate) _dbUpdatesByUser.get(user); if (update != null) { update.setSessionClosed(true); } } } catch (Throwable e) { WGFactory.getLogger().error("Setting session closed flag transaction on session close", e); } try { SessionStatus sessionStatus = (SessionStatus) _sessionStatus.get(); if (sessionStatus != null) { Session session = sessionStatus.getSession(); if (session != null) { session.disconnect(); session.close(); } } _sessionStatus.remove(); } catch (HibernateException e) { throw new WGBackendException("Error closing hibernate session", e); } } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#createContent(WGStructEntry, * WGLanguage, String) */ public WGDocumentCore createContent(WGStructEntry structEntry, WGLanguage language, String title, int version) throws WGAPIException { Content newContent = new Content(); // Additionally set object references, so they can be requested // instantly StructEntry structEntryEntity = (StructEntry) getEntity(structEntry); newContent.setStructentry(structEntryEntity); structEntryEntity.getContent().add(newContent); Language languageEntity = (Language) getEntity(language); newContent.setLanguage(languageEntity); // Initialize other data newContent.setVersion(new Integer(version)); newContent.setTitle(title); newContent.setItems(new HashMap()); newContent.setFiles(new HashMap()); newContent.setRelations(new HashMap()); newContent.setIshiddenfrom(new ArrayList()); newContent.setKeywords(new ArrayList()); newContent.setWfhistory(new ArrayList()); newContent.setVisible(new Boolean(true)); return createDocumentImpl(newContent); } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#createCopy(WGDocumentCore) */ public WGDocumentCore createCopy(WGDocumentCore originalCore) throws WGCreationException { WGDocumentImpl docOriginal = (WGDocumentImpl) originalCore; Object originalEntity = docOriginal.getEntity(); try { WGDocumentImpl docCopy = null; if (originalEntity instanceof Content) { Content original = (Content) originalEntity; Content copy = new Content(); copy.setTitle(original.getTitle()); copy.setLanguage(original.getLanguage()); copy.setStatus(original.getStatus()); copy.setStructentry(original.getStructentry()); copy.setVersion(original.getVersion()); copy.setVisible(original.isVisible()); docCopy = createDocumentImpl(copy); //entityCopy.save(new java.util.Date()); // Must save to append // other entities to it copy.setAuthor(original.getAuthor()); if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { copy.setContentclass(original.getContentclass()); copy.setOwner(original.getOwner()); copy.setCoauthors((List) cloneCollection(original.getCoauthors())); } copy.setDescription(original.getDescription()); copy.setLinktarget(original.getLinktarget()); copy.setUniquename(original.getUniquename()); copy.setValidfrom(original.getValidfrom()); copy.setValidto(original.getValidto()); copy.setVirtuallink(original.getVirtuallink()); copy.setVirtuallinktype(original.getVirtuallinktype()); copy.setIshiddenfrom((List) cloneCollection(original.getIshiddenfrom())); copy.setKeywords((List) cloneCollection(original.getKeywords())); copy.setReaders((List) cloneCollection(original.getReaders())); copy.setWfhistory((List) cloneCollection(original.getWfhistory())); docOriginal.pushFiles(docCopy); copy.setItems(cloneContentItems(original.getItems(), copy)); if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { copy.setRelations(cloneContentRelations(original.getRelations(), copy)); } if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { copy.setExtensionData(cloneExtensionData(original.getExtensionData(), copy)); } } else { throw new WGCreationException( "Copying of document type " + WGDocument.doctypeNumberToName(originalCore.getType()) + " is not supported in this database"); } return docCopy; } catch (Exception e) { throw new WGCreationException("Error creating entity copy", e); } } /** * @param map * @return */ private Map cloneContentItems(Map map, Content target) { Map itemCopies = new HashMap(); Iterator itemNames = map.keySet().iterator(); Object itemName; ContentItem contentItem; ContentItem contentItemCopy; while (itemNames.hasNext()) { itemName = itemNames.next(); contentItem = (ContentItem) map.get(itemName); contentItemCopy = new ContentItem(); contentItemCopy.setDate(contentItem.getDate()); contentItemCopy.setName(contentItem.getName()); contentItemCopy.setNumber(contentItem.getNumber()); contentItemCopy.setParentcontent(target); contentItemCopy.setText(contentItem.getText()); contentItemCopy.setType(contentItem.getType()); itemCopies.put(itemName, contentItemCopy); } return itemCopies; } /** * @param map * @return */ private Map cloneContentRelations(Map map, Content target) { Map itemCopies = new HashMap(); Iterator itemNames = map.keySet().iterator(); Object relName; ContentRelation contentItem; ContentRelation contentItemCopy; while (itemNames.hasNext()) { relName = itemNames.next(); contentItem = (ContentRelation) map.get(relName); contentItemCopy = new ContentRelation(); contentItemCopy.setName(contentItem.getName()); contentItemCopy.setGroup(contentItem.getGroup()); contentItemCopy.setParentcontent(target); contentItemCopy.setTargetlanguage(contentItem.getTargetlanguage()); contentItemCopy.setTargetstructentry(contentItem.getTargetstructentry()); contentItemCopy.setTarget(contentItem.getTarget()); itemCopies.put(relName, contentItemCopy); } return itemCopies; } public static Map<String, ExtensionData> cloneExtensionData(Map<String, ExtensionData> map, Entity target) { Map<String, ExtensionData> extensionDataCopies = new HashMap<String, ExtensionData>(); Iterator<String> edNames = map.keySet().iterator(); String edName; ExtensionData extensionData; ExtensionData exensionDataCopy; while (edNames.hasNext()) { edName = edNames.next(); extensionData = (ExtensionData) map.get(edName); exensionDataCopy = new ExtensionData(); exensionDataCopy.setEntity(target); exensionDataCopy.setDate(extensionData.getDate()); exensionDataCopy.setName(extensionData.getName()); exensionDataCopy.setNumber(extensionData.getNumber()); exensionDataCopy.setText(extensionData.getText()); exensionDataCopy.setType(extensionData.getType()); exensionDataCopy.setBinarySha512(extensionData.getBinarySha512()); extensionDataCopies.put(edName, exensionDataCopy); } return extensionDataCopies; } /** * @param list * @return */ private Collection cloneCollection(Collection col) { if (col == null) { return null; } if (col instanceof List) { List list = new ArrayList(); list.addAll((List) col); return list; } else if (col instanceof Set) { Set set = new HashSet(); set.addAll((Set) col); return set; } else if (col instanceof Bag) { Bag bag = new HashBag(); bag.addAll((Bag) col); return bag; } else { throw new IllegalArgumentException("Cannot clone collections of type: " + col.getClass().getName()); } } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#createDesignDocument(int, * String, String) */ public WGDocumentCore createDesignDocument(int type, String name, String mediaKey) throws WGAuthorisationException, WGCreationException { MainEntity newEntity = null; switch (type) { case WGDocument.TYPE_AREA: Area newArea = new Area(); newArea.setName(name); newArea.setReaders(new ArrayList()); newArea.setEditors(new ArrayList()); newArea.setRootentries(new HashMap()); newEntity = newArea; break; case WGDocument.TYPE_CONTENTTYPE: ContentType newContentType = new ContentType(); newContentType.setName(name); newContentType.setAllowedpositions(new ArrayList()); newEntity = newContentType; break; case WGDocument.TYPE_CSSJS: CSSJSModule newCSSJSModule = new CSSJSModule(); newCSSJSModule.setName(name); if (mediaKey != null) { newCSSJSModule.setCodetype(mediaKey); } newEntity = newCSSJSModule; break; case WGDocument.TYPE_FILECONTAINER: FileContainer newFileContainer = new FileContainer(); newFileContainer.setName(name); newFileContainer.setFiles(new HashMap()); newEntity = newFileContainer; break; case WGDocument.TYPE_LANGUAGE: Language newLanguage = new Language(); newLanguage.setName(name); newEntity = newLanguage; break; case WGDocument.TYPE_TML: TMLModule newTMLModule = new TMLModule(); newTMLModule.setModulekey(new TMLModuleKey(name, mediaKey)); newTMLModule.setDirectaccess(new Boolean(true)); newTMLModule.setCacheable(new Boolean(false)); newEntity = newTMLModule; break; } if (newEntity != null) { return createDocumentImpl(newEntity); } else { return null; } } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#createStructEntry(WGDocument, * WGContentType) */ public WGDocumentCore createStructEntry(Object key, WGDocument reference, WGContentType contentType) throws WGAPIException { StructEntry newStructEntry = new StructEntry(); if (contentType != null) { ContentType contentTypeEntity = (ContentType) ((WGDocumentImpl) contentType.getCore()).getEntity(); newStructEntry.setContenttype(contentTypeEntity); } if (key != null) { newStructEntry.setKey(String.valueOf(key)); } else { UUIDHexGenerator idGenerator = new UUIDHexGenerator(); newStructEntry.setKey(String.valueOf(idGenerator .generate((org.hibernate.engine.spi.SessionImplementor) getSession(), newStructEntry))); } if (reference instanceof WGArea) { Area area = (Area) ((WGDocumentImpl) reference.getCore()).getEntity(); newStructEntry.setArea(area); if (_ddlVersion < WGDatabase.CSVERSION_WGA5) { area.getRootentries().put(newStructEntry.getKey(), newStructEntry); } } else { StructEntry parentEntry = (StructEntry) getEntity(reference); newStructEntry.setParententry(parentEntry); if (_ddlVersion < WGDatabase.CSVERSION_WGA5) { parentEntry.getChildentries().put(newStructEntry.getKey(), newStructEntry); } } newStructEntry.setReaders(new ArrayList()); newStructEntry.setChildeditors(new ArrayList()); newStructEntry.setPageeditors(new ArrayList()); newStructEntry.setPublished(new HashMap()); newStructEntry.setContent(new HashSet()); newStructEntry.setChildentries(new HashMap()); return createDocumentImpl(newStructEntry); } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#createUserProfile(String, * int) */ public WGDocumentCore createUserProfile(String name, int type) throws WGAPIException, WGAuthorisationException, WGCreationException { UserProfile newProfile = new UserProfile(); if (name != null) { newProfile.setName(name); } else { UUIDHexGenerator idGenerator = new UUIDHexGenerator(); newProfile.setName(String.valueOf(idGenerator.generate((SessionImplementor) getSession(), newProfile))); } newProfile.setType(new Integer(type)); newProfile.setHits(new Integer(0)); newProfile.setSessions(new Integer(0)); newProfile.setLanguages(new ArrayList<String>()); newProfile.setPortletkeys(new ArrayList<String>()); newProfile.setItems(new HashMap<String, UserProfileItem>()); newProfile.setPortlets(new HashMap<String, UserProfilePortlet>()); return createDocumentImpl(newProfile); } /** * @throws WGAPIException * @throws WGIllegalArgumentException * @see de.innovationgate.webgate.api.WGDatabaseCore#fastAccess(Object) */ public WGDocumentCore fastAccess(int type, Object key) throws WGAPIException, WGIllegalArgumentException { if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { V5FastAccessKey v5Key = (V5FastAccessKey) key; if (v5Key.getId() != null) { Class clazz = getClassByType(v5Key.getType()); MainEntity entity = (MainEntity) getSession().get(clazz, v5Key.getId()); if (entity != null) { return createDocumentImpl(entity); } } return null; } else { if (key instanceof String) { String cuid = (String) key; Content content = null; try { content = (Content) getSession().get(Content.class, cuid); } catch (ObjectNotFoundException e) { return null; } catch (HibernateException e) { throw new WGBackendException("Error fast accessing content", e); } if (content != null) { return createDocumentImpl(content); } else { return null; } } else { throw new WGIllegalArgumentException("Parameter key must be an instance of String."); } } } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getAllContent(WGStructEntry) */ public List getAllContent(WGStructEntry structEntry, boolean includeArchived) throws WGAPIException { try { StructEntry hentry = (StructEntry) ((WGDocumentImpl) structEntry.getCore()).getEntity(); StringBuffer queryText = new StringBuffer(); queryText.append("select content from Content as content where content.structentry = :entry"); if (!includeArchived) { queryText.append(" and not content.status = 'a'"); } Query query = getSession().createQuery(queryText.toString()); query.setParameter("entry", hentry); Iterator contentIt = query.iterate(); List contentList = new ArrayList(); Content content = null; while (contentIt.hasNext()) { content = (Content) contentIt.next(); if (includeArchived || content.getStatus() != WGContent.STATUS_ARCHIVE) { contentList.add(createDocumentImpl(content)); } } return contentList; } catch (HibernateException e) { throw new WGBackendException("Exception retrieving struct entry content", e); } } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getChildEntries(WGStructEntry) */ public Iterator<WGDocumentCore> getChildEntries(WGStructEntry structEntry, WGPageOrderSet order) throws WGAPIException { StructEntry hentry = (StructEntry) ((WGDocumentImpl) structEntry.getCore()).getEntity(); Map<String, Object> params = new HashMap<String, Object>(); String orderClause; if (order != null && getCsVersion().getPatchLevel() > 4) { orderClause = buildHqlPageOrderClause(order, params); } else { if (order != null && getCsVersion().getPatchLevel() <= 4) { WGFactory.getLogger().warn("Order clause not allowed for CS PL < 5. Using default order."); } orderClause = "struct.position asc, struct.title asc, struct.key asc"; } Query query = getSession() .createQuery("select struct from StructEntry as struct where struct.parententry = :entry order by " + orderClause); params.put("entry", hentry); for (Map.Entry<String, Object> param : params.entrySet()) { query.setParameter(param.getKey(), param.getValue()); } return new StructEntryIterator(this, query); } protected String buildHqlPageOrderClause(WGPageOrderSet order, Map<String, Object> params) throws WGAPIException { List<String> hqlTerms = new ArrayList<String>(); WGDocumentImpl langDoc = null; String contentLanguage = order.getContentLanguage(); if (contentLanguage == null) { contentLanguage = _db.getDefaultLanguage(); } langDoc = (WGDocumentImpl) getDesignObject(WGDocument.TYPE_LANGUAGE, contentLanguage, null); if (langDoc == null) { throw new WGIllegalArgumentException("Undefined language: " + contentLanguage); } int itemNameIdx = 0; for (WGColumnSet.Term term : order.getTerms()) { String clause = null; if (Character.isUpperCase(term.getName().charAt(0))) { StringBuffer clauseTerm = new StringBuffer(); WGColumnSet.ColumnMeta columnMeta = WGColumnSet.COLUMN_METAS.get(term.getName()); if (columnMeta == null) { throw new WGIllegalArgumentException("Unknown column meta name: " + term.getName()); } for (Class<? extends WGDocument> loc : columnMeta.getLocations()) { if (loc == WGStructEntry.class) { clauseTerm.append("struct"); } else if (loc == WGContent.class) { params.put("langentity", langDoc.getEntity()); clauseTerm.append("struct.releasedcontent[:langentity]"); } else if (loc == WGContentType.class) { clauseTerm.append("struct.contenttype"); } else if (loc == WGLanguage.class) { params.put("langentity", langDoc.getEntity()); clauseTerm.append("struct.releasedcontent[:langentity].language"); } else { continue; } clauseTerm.append(".").append(columnMeta.getMetaName().toLowerCase()); // Metas with special data structures if (loc == WGStructEntry.class && term.getName().equals("PAGEPUBLISHED")) { params.put("lang", contentLanguage); clauseTerm.append("[:lang]"); } clause = clauseTerm.toString(); break; } } else { itemNameIdx++; params.put("itemname" + itemNameIdx, term.getName()); String property = term.getFlags().containsKey("type") ? term.getFlags().get("type") : "text"; params.put("langentity", langDoc.getEntity()); clause = "struct.releasedcontent[:langentity].items[:itemname" + itemNameIdx + "]." + property; } if (clause != null) { if ("true".equals(term.getFlags().get("ci"))) { clause = "lower(" + clause + ")"; } if ("true".equals(term.getFlags().get("desc"))) { clause += " desc"; } else { clause += " asc"; } hqlTerms.add(clause); } } String completeClause = WGUtils.serializeCollection(hqlTerms, ", "); return completeClause; } protected String buildHqlContentOrderClause(String contentExpression, WGColumnSet order, Map<String, Object> params) throws WGAPIException { List<String> hqlTerms = new ArrayList<String>(); WGDocumentImpl langDoc = null; int itemNameIdx = 0; for (WGColumnSet.Term term : order.getTerms()) { String clause = null; if (Character.isUpperCase(term.getName().charAt(0))) { StringBuffer clauseTerm = new StringBuffer(); WGColumnSet.ColumnMeta columnMeta = WGColumnSet.COLUMN_METAS.get(term.getName()); if (columnMeta == null) { throw new WGIllegalArgumentException("Unknown column meta name: " + term.getName()); } for (Class<? extends WGDocument> loc : columnMeta.getLocations()) { if (loc == WGStructEntry.class) { clauseTerm.append(contentExpression).append(".structentry"); } else if (loc == WGContent.class) { clauseTerm.append(contentExpression); } else if (loc == WGContentType.class) { clauseTerm.append(contentExpression).append(".structentry.contenttype"); } else if (loc == WGLanguage.class) { clauseTerm.append(contentExpression).append(".language"); } else { continue; } clauseTerm.append(".").append(columnMeta.getMetaName().toLowerCase()); // Metas with special data structures if (loc == WGStructEntry.class && term.getName().equals(WGStructEntry.META_PUBLISHED)) { clauseTerm.append("[content.language.name]"); } clause = clauseTerm.toString(); break; } } else { itemNameIdx++; params.put("itemname" + itemNameIdx, term.getName()); String property = term.getFlags().containsKey("type") ? term.getFlags().get("type") : "text"; clause = contentExpression + ".items[:itemname" + itemNameIdx + "]." + property; } if (clause != null) { if ("true".equals(term.getFlags().get("ci"))) { clause = "lower(" + clause + ")"; } if ("true".equals(term.getFlags().get("desc"))) { clause += " desc"; } else { clause += " asc"; } hqlTerms.add(clause); } } return WGUtils.serializeCollection(hqlTerms, ", "); } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getContentByKey(WGContentKey) */ public WGDocumentCore getContentByKey(WGContentKey key) throws WGAPIException { try { Query contentQuery; if (key.getVersion() != 0) { contentQuery = getSession().createQuery( "from Content as content where content.structentry.key =:structkey and content.language.name =:lang and content.version =:version"); contentQuery.setInteger("version", key.getVersion()); } else { contentQuery = getSession().createQuery( "from Content as content where content.structentry.key =:structkey and content.language.name =:lang and content.status ='p'"); } contentQuery.setString("structkey", String.valueOf(key.getStructKey())); contentQuery.setString("lang", key.getLanguage()); Iterator it = contentQuery.iterate(); if (it.hasNext()) { Content content = (Content) it.next(); return createDocumentImpl(content); } else { return null; } } catch (HibernateException e) { throw new WGBackendException("Error loading content by key", e); } } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getContentByName(String, * String) */ public WGDocumentCore getContentByName(String strName, String strLanguage) throws WGAPIException { strName = strName.toLowerCase(); strLanguage = (strLanguage != null ? strLanguage.toLowerCase() : null); String queryStr = "from Content as content where content.status='p' and content.uniquename=:name"; if (strLanguage != null) { queryStr += " and content.language.name=:lang"; } Iterator contents; try { Query query = getSession().createQuery(queryStr); query.setString("name", strName); if (strLanguage != null) { query.setString("lang", strLanguage); } contents = query.iterate(); } catch (HibernateException e) { throw new WGBackendException("Error searching content by name", e); } Content content; if (contents.hasNext()) { content = (Content) contents.next(); return createDocumentImpl(content); } return null; } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#getDedicatedWorkflowEngine() */ public Class getDedicatedWorkflowEngine() { return null; } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getDesignObject(int, * String, String) */ public WGDocumentCore getDesignObject(int type, String name, String strMediaKey) throws WGAPIException { Class designClass = getClassByType(type); MainEntity design = null; try { if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { design = getDesignObjectV5(name, strMediaKey, designClass); } else { design = getDesignObjectV4(name, strMediaKey, designClass); } } catch (ObjectNotFoundException e) { return null; } catch (ObjectDeletedException e) { return null; } catch (HibernateException e) { throw new WGBackendException("Error retrieving design object", e); } if (design != null) { return createDocumentImpl(design); } else { return null; } } private MainEntity getDesignObjectV5(String name, String strMediaKey, Class designClass) throws WGAPIException { Criteria crit = getSession().createCriteria(designClass); crit.add(Restrictions.eq("name", name)); if (designClass == TMLModule.class) { crit.add(Restrictions.eq("mediakey", strMediaKey)); } else if (designClass == CSSJSModule.class) { crit.add(Restrictions.eq("codetype", strMediaKey)); } List results = crit.list(); if (results.size() > 0) { return (MainEntity) results.get(0); } else { return null; } } private MainEntity getDesignObjectV4(String name, String strMediaKey, Class designClass) throws WGAPIException { MainEntity design; if (designClass == TMLModule.class) { design = (MainEntity) getSession().get(designClass, new TMLModuleKey(name, strMediaKey)); } else { design = (MainEntity) getSession().get(designClass, name); } return design; } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getDesignObjects(int) */ public List getDesignObjects(int type) throws WGAPIException { String query = "from " + getClassByType(type).getName() + " as design"; Iterator designs; try { designs = getSession().createQuery(query).iterate(); } catch (HibernateException e) { throw new WGBackendException("Error retrieving design objects.", e); } List designList = new ArrayList(); while (designs.hasNext()) { designList.add(createDocumentImpl((MainEntity) designs.next())); } return designList; } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#getDummyContent(String) */ public WGDocumentCore getDummyContent(String language) { return new de.innovationgate.webgate.api.fake.WGDummyContent(this._db, language); } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getRevision() */ public Comparable getRevision() throws WGAPIException { try { List result; if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { //Sequence seq = (Sequence) getSession().get(Sequence.class, "historylog_id"); //if (seq != null) { //return (seq.getValue() - 1); //} result = getSession().createQuery("select max(entry.id) from LogEntry as entry").list(); if (result.size() > 0) { Long id = (Long) result.get(0); if (id != null) { return id; } } return Long.MIN_VALUE; } else { result = getSession().createQuery("select max(entry.logtime) from LogEntry as entry").list(); Date lcDate = null; if (result.size() > 0) { lcDate = (Date) result.get(0); } if (lcDate != null) { return lcDate; } else { return new Date(Long.MIN_VALUE); } } } catch (HibernateException e) { throw new WGBackendException("Error retrieving historylog of database '" + getTitle() + "'", e); } } /** * @throws WGIllegalArgumentException * @throws WGAPIException * @throws WGSystemException * @see de.innovationgate.webgate.api.WGDatabaseCore#getExtensionData(String) */ public Object getExtensionData(String name) throws WGAPIException { name = name.toLowerCase().trim(); ExtensionData md = retrieveExtensionData(name); if (md != null) { getSession().refresh(md); return WGDocumentImpl.readItemValue(this, null, md); } else { return null; } } private ExtensionData retrieveExtensionData(String name) throws WGAPIException { ExtensionData md = null; Criteria c = getSession().createCriteria(ExtensionData.class); c.add(Restrictions.eq("name", name)); c.add(Restrictions.isNull("entity")); List<ExtensionData> results = c.list(); if (results.size() > 0) { md = results.get(0); } return md; } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#getNewDesignsSince(Date) */ public List getNewDesignsSince(Date date) { return null; } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getParentEntry(WGStructEntry) */ public WGDocumentCore getParentEntry(WGStructEntry entry) throws WGAPIException { StructEntry hentry = (StructEntry) ((WGDocumentImpl) entry.getCore()).getEntity(); StructEntry parent = (StructEntry) hentry.getParententry(); if (parent != null) { try { return createDocumentImpl(parent); } catch (UnresolvableObjectException e) { WGFactory.getLogger() .error("Struct entry with unresolveable parent entry: " + entry.getDocumentKey()); // Apparently Hibernate also returns a parent StructEntry if it is no longer available // In the database. We catch this here silently, though there is a doc with non-integer // parent hierarchy here. } } return null; } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#getRoles() */ public List getRoles() { return Arrays.asList(new String[] { WGDatabase.ROLE_CONTENT, WGDatabase.ROLE_DESIGN, WGDatabase.ROLE_REPOSITORY, WGDatabase.ROLE_USERPROFILES }); } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getRootEntries(WGArea) */ public Iterator<WGDocumentCore> getRootEntries(WGArea area, WGPageOrderSet order) throws WGAPIException { Area harea = (Area) ((WGDocumentImpl) area.getCore()).getEntity(); Map<String, Object> params = new HashMap<String, Object>(); String orderClause; if (order != null) { orderClause = buildHqlPageOrderClause(order, params); } else { orderClause = "struct.position asc, struct.title asc, struct.key asc"; } Query query = getSession().createQuery( "select struct from StructEntry as struct where struct.area = :area order by " + orderClause); params.put("area", harea); for (Map.Entry<String, Object> param : params.entrySet()) { query.setParameter(param.getKey(), param.getValue()); } return new StructEntryIterator(this, query); } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getStructEntryByKey(Object) */ public WGDocumentCore getStructEntryByKey(Object key) throws WGAPIException { try { StructEntry entry = null; if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { Criteria crit = getSession().createCriteria(StructEntry.class); crit.add(Restrictions.eq("key", String.valueOf(key))); List results = crit.list(); if (results.size() > 0) { entry = (StructEntry) results.get(0); } } else { entry = (StructEntry) getSession().get(StructEntry.class, (String) key); } if (entry != null) { return createDocumentImpl(entry); } else { return null; } } catch (ObjectNotFoundException e) { return null; } catch (HibernateException e) { throw new WGBackendException("Error loading structentry by key", e); } } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#getTitle() */ public String getTitle() { return _path; } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#getTypeName() */ public String getTypeName() { return DBTYPE; } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#getUserProfile(String) */ public WGDocumentCore getUserProfile(String name) throws WGAPIException { try { UserProfile profile = null; if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { Criteria q = getSession().createCriteria(UserProfile.class); q.add(Restrictions.eq("name", name)); List results = q.list(); if (results.size() > 0) { profile = (UserProfile) results.get(0); } } else { profile = (UserProfile) getSession().get(UserProfile.class, name); } if (profile != null) { return createDocumentImpl(profile); } else { return null; } } catch (ObjectNotFoundException e) { return null; } catch (HibernateException e) { throw new WGBackendException("Error loading userprofile for name '" + name + "'.", e); } } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#hasFeature(String) */ public boolean hasFeature(String feature) { if (feature.equals(WGDatabase.FEATURE_EDITABLE) || feature.equals(WGDatabase.FEATURE_FULLCONTENTFEATURES) || feature.equals(WGDatabase.FEATURE_HIERARCHICAL) || feature.equals(WGDatabase.FEATURE_QUERYABLE) || feature.equals(WGDatabase.FEATURE_USE_OBJECTS_AS_REFERENCES) || feature.equals(WGDatabase.FEATURE_LASTCHANGED) || feature.equals(WGDatabase.FEATURE_GENERATES_STRUCTKEYS) || feature.equals(WGDatabase.FEATURE_ACCEPTS_STRUCTKEYS) || feature.equals(WGDatabase.FEATURE_MULTILANGUAGE) || feature.equals(WGDatabase.FEATURE_ACL_MANAGEABLE) || feature.equals(WGDatabase.FEATURE_COMPLEXVALUES) || feature.equals(WGDatabase.FEATURE_FIND_UPDATED_DOCS) || feature.equals(WGDatabase.FEATURE_RETRIEVE_ALL_CONTENTKEYS) || feature.equals(WGDatabase.FEATURE_QUERY_PROFILES) || feature.equals(WGDatabase.FEATURE_EXTERNAL_AUTHENTICATION) || feature.equals(WGDatabase.FEATURE_VALIDATE_ATTACHMENTS) || feature.equals(WGDatabase.FEATURE_SELF_PERSONALIZABLE) || feature.equals(WGDatabase.FEATURE_UNLIMITED_CORES) || feature.equals(WGDatabase.FEATURE_TRANSACTIONS) || feature.equals(WGDatabase.FEATURE_ORDERED_NAVIGATION_RESULTS) || feature.equals(WGDatabase.FEATURE_CONTENT_READ_PROTECTION)) { return true; } else if (feature.equals(WGDatabase.FEATURE_LOADBALANCE)) { if (_db.getCreationOptions().get(COPTION_LOADBALANCE) != null && Boolean.valueOf((String) _db.getCreationOptions().get(COPTION_LOADBALANCE)).booleanValue()) { return true; } else { return false; } } else if (feature.equals(WGDatabase.FEATURE_DIRECT_ENTITY_READDING)) { return _saveIsolationActive; } else if (feature.equals(WGDatabase.FEATURE_PROVIDE_PORTLETITEM_STORAGE)) { return _ddlVersion >= WGDatabase.CSVERSION_WGA5; } else if (feature.equals(WGDatabase.FEATURE_CONTENT_FILE_DERIVATES)) { return (_fileHandling instanceof CS5P4FileHandling); } else { return false; } } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#isMemberOfUserList(List) */ public boolean isMemberOfUserList(List userList) throws WGAPIException { return _db.defaultIsMemberOfUserList(userList); } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#open(WGDatabase, * String, String, String, boolean) */ public WGUserAccess open(WGDatabase db, String path, String user, String pwd, boolean prepareOnly) throws WGAPIException { try { this._db = db; this._path = path; this._aclImpl = new ACLImpl(this); String jdbcDriver = (String) db.getCreationOptions().get("Driver"); if (jdbcDriver == null) { jdbcDriver = (String) db.getCreationOptions().get("hibernate.connection.driver_class"); } // Determine dll version _csVersion = determineCSVersion(db, jdbcDriver, path, user, pwd); _ddlVersion = _csVersion.getVersion(); _fileHandling = createFileHandling(); boolean useSharedPool = WGUtils.getBooleanMapValue(db.getCreationOptions(), WGDatabase.COPTION_SHAREDPOOL, true); if (useSharedPool && db.getCreationOptions().containsKey(Database.OPTION_PATH) && db.getServer() instanceof SharedPoolJDBCDatabaseServer) { SharedPoolJDBCDatabaseServer poolServer = (SharedPoolJDBCDatabaseServer) db.getServer(); if (poolServer.isPoolAvailable(_csVersion)) { try { _connProvider = poolServer.createPoolConnectionProvider( (String) db.getCreationOptions().get(Database.OPTION_PATH)); WGFactory.getLogger() .info("Database '" + db.getDbReference() + "' uses the shared connection pool of database server '" + db.getServer().getTitle(Locale.getDefault()) + "'"); } catch (WGInvalidDatabaseException e) { throw e; } catch (Exception e) { throw new WGInvalidDatabaseException("Exception connecting to shared database server pool", e); } } } // Create regular connection provider if no shared one available/allowed if (_connProvider == null) { Properties props = new Properties(); if (path.startsWith("jdbc:")) { putDefaultConPoolProps(db, props); } if (user != null || pwd != null) { props.put("hibernate.connection.username", WGUtils.getValueOrDefault(user, "")); props.put("hibernate.connection.password", WGUtils.getValueOrDefault(pwd, "")); } String driverClass = (String) db.getCreationOptions().get("Driver"); props.put(Environment.ISOLATION, String.valueOf(Connection.TRANSACTION_READ_COMMITTED)); props.putAll(db.getCreationOptions()); try { _connProvider = new JDBCConnectionProvider(path, driverClass, props, true); } catch (JDBCConnectionException e) { throw new WGInvalidDatabaseException("Exception creating connection pool", e); } } // Build Session factory and builder buildSessionFactory(db, path, user, pwd, _csVersion, _connProvider); if ("true".equals(System.getProperty("de.innovationgate.wga.hibernate.enable_jmx"))) { _sessionFactory.getStatistics().setStatisticsEnabled(true); try { Object statisticsMBean = Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[] { StatisticsMXBean.class }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(_sessionFactory.getStatistics(), args); } }); _jmxManager = new JmxManager(statisticsMBean, new ObjectName("de.innovationgate.WGAMonitor:name=Hibernate-Statistics,db=" + JmxManager.normalizeJmxKey(db.getDbReference()))); } catch (Exception e2) { WGFactory.getLogger().error("Exception enabling JMX for Hibernate statistics", e2); } } _sessionBuilder = _sessionFactory.withOptions(); // Determine save isolation _saveIsolationActive = _ddlVersion >= WGDatabase.CSVERSION_WGA5; if (db.getCreationOptions().containsKey("SaveIsolation")) { _saveIsolationActive = Boolean.parseBoolean((String) db.getCreationOptions().get("SaveIsolation")); } // parse masterPersistenceTimeout if (db.getCreationOptions().containsKey(COPTION_MASTERPERSISTENCE_TIMEOUT)) { _masterPersistenceTimeout = Long .parseLong((String) db.getCreationOptions().get(COPTION_MASTERPERSISTENCE_TIMEOUT)); } // parse HQL query default type String hqlType = (String) db.getCreationOptions().get(COPTION_HQL_FETCH_TYPE); if (hqlType != null) { _hqlLazyByDefault = hqlType.equals(HQL_FETCHTYPE_LAZY); } String hqlLazyParentCheck = (String) db.getCreationOptions().get(COPTION_HQL_LAZY_PARENTCHECK); if (hqlLazyParentCheck != null) { _hqlLazyParentCheck = Boolean.parseBoolean(hqlLazyParentCheck); } // open session WGUserAccess accessLevel; try { accessLevel = openSession(MasterLoginAuthSession.getInstance(), pwd, true); } catch (WGUnavailableException e) { throw new WGInvalidDatabaseException("Error opening initial session", e); } catch (WGBackendException e) { throw new WGInvalidDatabaseException("Error opening initial session", e); } if (accessLevel.getAccessLevel() <= WGDatabase.ACCESSLEVEL_NOACCESS) { try { close(); } catch (WGBackendException e1) { WGFactory.getLogger().error(e1); } } return accessLevel; } catch (WGInvalidDatabaseException e) { if (_connProvider != null) { if (_connProvider instanceof Stoppable) { ((Stoppable) _connProvider).stop(); } _connProvider = null; } throw e; } } protected FileHandling createFileHandling() { FileHandling fileHandling; if (_csVersion.getVersion() >= WGDatabase.CSVERSION_WGA5) { if (_csVersion.getPatchLevel() >= 5) { fileHandling = new CS5P5FileHandling(); } else if (_csVersion.getPatchLevel() >= 4 && !"false".equals(_db.getCreationOptions().get(COPTION_DISTINCTFILECONTENTS))) { fileHandling = new CS5P4FileHandling(); } else { fileHandling = new CS5FileHandling(); } } else if (_csVersion.getVersion() >= WGDatabase.CSVERSION_WGA4_1) { fileHandling = new CS41FileHandling(); } else { fileHandling = new CS3FileHandling(); } fileHandling.init(this); return fileHandling; } private void buildSessionFactory(WGDatabase db, String path, String user, String pwd, CSVersion version, ConnectionProvider connProvider) throws WGInvalidDatabaseException { // Move old Hibernate2 packages to Hibernate3 packages Iterator dbOptionsIt = db.getCreationOptions().keySet().iterator(); while (dbOptionsIt.hasNext()) { Object key = dbOptionsIt.next(); String value = (String) db.getCreationOptions().get(key); if (value != null && value.startsWith("net.sf.hibernate.")) { value = "org.hibernate." + value.substring(17); db.getCreationOptions().put(key, value); } } // Determine mapping file _conf = new Configuration(); try { if (db.getCreationOptions().containsKey(DBOPTION_MAPPINGFILE)) { File mappingFile = new File((String) db.getCreationOptions().get(DBOPTION_MAPPINGFILE)); if (!mappingFile.exists() || !mappingFile.isFile()) { throw new WGInvalidDatabaseException( "Configured mapping file '" + db.getCreationOptions().get(DBOPTION_MAPPINGFILE) + "' does not exist or is no valid file."); } _conf.addFile(mappingFile); } else if (db.getCreationOptions().containsKey(DBOPTION_MAPPINGRESOURCE)) { _conf.addResource((String) db.getCreationOptions().get(DBOPTION_MAPPINGRESOURCE), this.getClass().getClassLoader()); } else if (_ddlVersion == WGDatabase.CSVERSION_WGA5) { int patchLevel = version.getPatchLevel(); String mappingFile = getCS5PatchLevelMappingFile(patchLevel); _conf.addResource(mappingFile, this.getClass().getClassLoader()); } else if (_ddlVersion == WGDatabase.CSVERSION_WGA4_1) { _conf.addResource(HIBERNATE_V41_MAPPING_FILE, this.getClass().getClassLoader()); } else { _conf.addResource(HIBERNATE_V3_MAPPING_FILE, this.getClass().getClassLoader()); } } catch (MappingException e) { throw new WGInvalidDatabaseException("Exception parsing hibernate mapping", e); } // Some options _conf.buildMappings(); if (db.getCreationOptions().containsKey(DBOPTION_HISTORYLOG_IDRANGE)) { Integer idRange = Integer.parseInt((String) db.getCreationOptions().get(DBOPTION_HISTORYLOG_IDRANGE)); Properties generatorProps = ((SimpleValue) _conf.getClassMapping(LogEntry.class.getName()) .getIdentifier()).getIdentifierGeneratorProperties(); generatorProps.setProperty("optimizer", "pooled-lo"); generatorProps.setProperty("increment_size", String.valueOf(idRange)); } Properties props = new Properties(); props.putAll(db.getCreationOptions()); _conf.addProperties(props); ServiceRegistryBuilder registryBuilder = new ServiceRegistryBuilder(); registryBuilder.applySettings(_conf.getProperties()); registryBuilder.addService(ConnectionProvider.class, connProvider); ServiceRegistryImplementor serviceRegistry = (ServiceRegistryImplementor) registryBuilder .buildServiceRegistry(); _conf.buildMappings(); // Some options if ("true".equals(db.getCreationOptions().get(DBOPTION_USE_GALERA_OPTIMIZATIONS))) { ((SimpleValue) _conf.getClassMapping(LogEntry.class.getName()).getIdentifier()) .setIdentifierGeneratorStrategy(GaleraClusterTableGenerator.class.getName()); } // Create session factory try { _sessionFactory = _conf.buildSessionFactory(serviceRegistry); } catch (HibernateException e) { throw new WGInvalidDatabaseException("Error creating session factory: " + e.getMessage(), e); } } public static String getCS5PatchLevelMappingFile(int patchLevel) { if (patchLevel >= 5) { return HIBERNATE_V5_P5_MAPPING_FILE; } else if (patchLevel >= 4) { return HIBERNATE_V5_P4_MAPPING_FILE; } else if (patchLevel >= 3) { return HIBERNATE_V5_P3_MAPPING_FILE; } else if (patchLevel >= 2) { return HIBERNATE_V5_P2_MAPPING_FILE; } else { return HIBERNATE_V5_MAPPING_FILE; } } /** * @param db * @param jdbcDriver * @param path * @param userName * @param password * @return * @throws WGInvalidDatabaseException */ /** * @param db * @param jdbcDriver * @param path * @param userName * @param password * @return * @throws WGInvalidDatabaseException */ private CSVersion determineCSVersion(WGDatabase db, String jdbcDriver, String path, String userName, String password) throws WGInvalidDatabaseException { try { JDBCConnectionProvider connProvider = createConnectionProvider(db, jdbcDriver, path, userName, password); try { // Determine content store version either by creation option or by inspecting backend database double version; String optionVersionStr = (String) db.getCreationOptions() .get(WGDatabase.COPTION_CONTENT_STORE_VERSION); if (optionVersionStr != null) { double optionVersion = Double.parseDouble(optionVersionStr); if (optionVersion == WGDatabase.CSVERSION_WGA3 || optionVersion == WGDatabase.CSVERSION_WGA4_1 || optionVersion == WGDatabase.CSVERSION_WGA5) { version = optionVersion; } else { version = determineCSVersion(connProvider); } } else { version = determineCSVersion(connProvider); } // Determine patch level int patchLevel = 0; if (version == WGDatabase.CSVERSION_WGA5) { patchLevel = determinePatchLevel(connProvider); } // Optionally execute hot patch String hotPatchPath = (String) db.getCreationOptions().get(COPTION_HOTPATCH); if (hotPatchPath != null) { try { HotPatchCollection hotPatch = HotPatchCollection.load(new File(hotPatchPath)); if (hotPatch != null) { for (HotPatch patch : hotPatch.getPatches()) { Class<?> csType = WGFactory.getImplementationLoader().loadClass(patch.getCsType()); if (csType.isAssignableFrom(getClass()) && patch.getCsVersion() == version && patch.getCsPatchLevel() == patchLevel) { connProvider.performHotPatch(patch); } } } } catch (Exception e) { WGFactory.getLogger().error("Exception loading hot patch", e); } } return new CSVersion(version, patchLevel); } finally { connProvider.stop(); } } catch (JDBCConnectionException e) { throw new WGInvalidDatabaseException("Exception connecting to database on path " + path, e); } catch (SQLException e) { throw new WGInvalidDatabaseException("Exception connecting to database on path " + path, e); } } protected JDBCConnectionProvider createConnectionProvider(WGDatabase db, String jdbcDriver, String path, String userName, String password) throws JDBCConnectionException { Properties props = new Properties(); Map creationOptions = db.getCreationOptions(); Iterator optsIt = creationOptions.keySet().iterator(); while (optsIt.hasNext()) { String option = (String) optsIt.next(); if (option.startsWith(("jdbc."))) { props.put("hibernate.connection." + option.substring(5), creationOptions.get(option)); } else { props.put(option, creationOptions.get(option)); } } props.put("user", WGUtils.getValueOrDefault(userName, "")); props.put("password", WGUtils.getValueOrDefault(password, "")); JDBCConnectionProvider connProvider = new JDBCConnectionProvider(path, jdbcDriver, props, false); return connProvider; } protected double determineCSVersion(JDBCConnectionProvider connProvider) throws SQLException { List<String> tables = connProvider.getDatabaseTables(); if (tables.contains(getCS5IndicatorTable())) { return WGDatabase.CSVERSION_WGA5; } else if (tables.contains(getCS41IndicatorTable())) { return WGDatabase.CSVERSION_WGA4_1; } // This is a new HSQL content store to be created - Currently we create CS5 by default else if (this instanceof de.innovationgate.webgate.api.hsql.WGDatabaseImpl & tables.size() == 0) { return WGDatabase.CSVERSION_WGA5; } else { return WGDatabase.CSVERSION_WGA3; } } private int determinePatchLevel(JDBCConnectionProvider connProvider) { int patchLevel = 0; Statement stmt = null; ResultSet res = null; try { stmt = connProvider.getConnection().createStatement(); res = stmt.executeQuery( "SELECT datatype, numbervalue, textvalue FROM extensiondata WHERE entity_id IS NULL AND name='" + DBMETA_PATCH_LEVEL.toLowerCase() + "'"); if (res.next()) { int type = res.getInt(1); Double numberValue = res.getDouble(2); String textValue = res.getString(3); if (type == WGDocumentImpl.ITEMTYPE_NUMBER) { patchLevel = numberValue.intValue(); } else if (type == WGDocumentImpl.ITEMTYPE_SERIALIZED_XSTREAM) { XStream xstream = new XStream(new Dom4JDriver()); patchLevel = ((Number) xstream.fromXML(textValue)).intValue(); } } } catch (Exception e) { WGFactory.getLogger().error("Exception determining CS5 patch level", e); } finally { try { if (res != null) { res.close(); } if (stmt != null) { stmt.close(); } } catch (Exception e) { WGFactory.getLogger().error("Exception closing resource for CS version determination", e); } } return patchLevel; } protected String getCS5IndicatorTable() { return "extensiondata"; } protected String getCS41IndicatorTable() { return "content_files_meta"; } protected String getCS3MappingFile() { return HIBERNATE_V3_MAPPING_FILE; } protected String getCS41MappingFile() { return HIBERNATE_V41_MAPPING_FILE; } /** * @throws WGUnavailableException * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#openSession(String, * String) */ public WGUserAccess openSession(AuthenticationSession authSession, Object pwd, boolean master) throws WGAPIException { try { // Hibernate login Session session = _sessionBuilder.openSession(); // Connection conn = session.connection(); // conn.setAutoCommit(true); //Problematic with DBCP? session.setFlushMode(FlushMode.COMMIT); if (_saveIsolationActive) { session.setDefaultReadOnly(true); } getSessionStatus().setSession(session); if (!session.isOpen()) { throw new WGUnavailableException(_db, "Unable to connect to hibernate session"); } // special handling if loadbalancing is enabled if (hasFeature(WGDatabase.FEATURE_LOADBALANCE)) { // set all connections to readonly except master sessions and if // update is in progress final boolean readOnly = (master ? false : !isUpdateInProgress(authSession.getDistinguishedName())); try { session.doWork(new Work() { public void execute(Connection connection) throws SQLException { connection.setReadOnly(readOnly); } }); } catch (HibernateException e) { throw new WGBackendException("Unable to set readonly flag on connection.", e); } } if (getTransactionMode() != WGSessionContext.TRANSACTION_MODE_MANUAL) { session.beginTransaction(); } if (master) { // Master login always has manager access return new WGUserAccess(WGDatabase.MASTER_USERNAME, WGDatabase.ACCESSLEVEL_MANAGER); } // Determine access WGUserDetails userDetails; try { userDetails = _db.defaultBuildUserDetails(authSession); } catch (WGBackendException e) { try { closeSession(); } catch (WGBackendException e1) { WGFactory.getLogger().error(e1); } throw e; } if (userDetails.getAccessLevel() <= WGDatabase.ACCESSLEVEL_NOACCESS) { try { closeSession(); } catch (WGBackendException e) { WGFactory.getLogger().error(e); } } return userDetails; } catch (HibernateException e) { try { closeSession(); } catch (WGBackendException e1) { WGFactory.getLogger().error(e1); } throw new WGUnavailableException(_db, "Error opening hibernate session", e); } } private int getTransactionMode() { if (_db.getSessionContext() != null) { return _db.getSessionContext().getTransactionMode(); } else { return WGSessionContext.TRANSACTION_MODE_DEFAULT; } } /** * @see de.innovationgate.webgate.api.WGDatabaseCore#parseStructKey(String) */ public Object parseStructKey(String key) { return key; } /** * @throws WGAPIException * @see de.innovationgate.webgate.api.WGDatabaseCore#query(String, String, * Map) */ public WGResultSetCore query(String type, String query, Map params) throws WGAPIException { if (type == null) { type = "hql"; } if (type.equals("native")) { type = "hql"; } if (type.equals("hql") || type.equals("fullhql")) { return executeHQLQuery(type, query, params); } else if (type.equals("fulltext")) { return executeFulltextQuery(query, params); } else if (type.equals("sql")) { return executeSQLQuery(query, params); } else { throw new WGQueryException(query, "Unknown query type: " + type); } } /** * @param query * @param params * @return * @throws WGAPIException */ private WGResultSetCore executeFulltextQuery(String query, Map params) throws WGAPIException { // Build base query query = WGUtils.strReplace(query, "'", "''", true); params.put(WGDatabase.QUERYOPTION_RETURNQUERY, query); StringBuffer builtQuery = createFulltextQuery(query); // Additions based on params if (params.containsKey(WGDatabase.QUERYOPTION_ONLYRELEASED)) { builtQuery.append(" and content.status = 'p'"); } if (params.containsKey(WGDatabase.QUERYOPTION_ONLYLANGUAGE)) { builtQuery.append(" and languages.name = '") .append(params.get(WGDatabase.QUERYOPTION_ONLYLANGUAGE).toString()).append("'"); } if (params.containsKey(WGDatabase.QUERYOPTION_EXCLUDEDOCUMENT)) { WGContent content = (WGContent) params.get(WGDatabase.QUERYOPTION_EXCLUDEDOCUMENT); if (content.getDatabase() == this._db) { WGDocumentCore contentCore = content.getCore(); if (contentCore instanceof WGDocumentImpl) { Content contentEntity = (Content) ((WGDocumentImpl) content.getCore()).getEntity(); builtQuery.append(" and not (content.cuid = '" + contentEntity.getCuid() + "')"); } } } // Execute query String fullQuery = builtQuery.toString(); return executeSQLQuery(fullQuery, params); } private WGResultSetCore executeSQLQuery(String fullQuery, Map queryOptions) throws WGAPIException { try { queryOptions.put(WGDatabase.QUERYOPTION_RETURNQUERY, fullQuery); SQLQuery hibQuery = getSession().createSQLQuery(fullQuery); if (fullQuery.contains("{")) { hibQuery.addEntity("content", Content.class); } Map queryParams = (Map) queryOptions.get(WGDatabase.QUERYOPTION_QUERY_PARAMETERS); HibernateResultSet.injectQueryParams(hibQuery, queryParams); return new WGSQLResultSet(this, hibQuery, queryParams, queryOptions); } catch (SQLGrammarException e) { throw new WGQueryException(fullQuery, e.getMessage(), e); } catch (HibernateException e) { throw new WGBackendException("Error executing SQL query", e); } } private StringBuffer createFulltextQuery(String query) { StringBuffer builtQuery = new StringBuffer(); builtQuery.append( "select {content.*} from content {content} left outer join content_items on content.cuid = content_items.cuid inner join languages on content.language = languages.name where (content.title like '%"); builtQuery.append(query); builtQuery.append("%' or content.description like '%"); builtQuery.append(query); builtQuery.append("%' or content_items.textvalue like '%"); builtQuery.append(query); builtQuery.append("%')"); return builtQuery; } private WGResultSetCore executeHQLQuery(String type, String query, Map queryOptions) throws WGAPIException { String builtQuery = null; Map queryParams = (Map) queryOptions.get(WGDatabase.QUERYOPTION_QUERY_PARAMETERS); if (queryParams == null) { queryParams = new HashMap(); } List<WGLanguage> languagesPriorityList = null; // Determine fetch type. Lazy fetch will only retrieve content keys and // get content data in subsequent calls List options = WGUtils.deserializeCollection( String.valueOf(queryOptions.get(WGDatabase.QUERYOPTION_NATIVEOPTIONS)), ",", true); boolean lazyFetch = _hqlLazyByDefault; if (options.contains(HQL_FETCHTYPE_STRAIGHT)) { lazyFetch = false; } else if (options.contains(HQL_FETCHTYPE_LAZY)) { lazyFetch = true; } if (type.equals("fullhql")) { builtQuery = query; } if (type.equals("hql")) { List fullQuery = new ArrayList(); // Filter invisible and unreleased docs if (!queryOptions.containsKey(WGDatabase.QUERYOPTION_ENHANCE) || String.valueOf(queryOptions.get(WGDatabase.QUERYOPTION_ENHANCE)).equals("true")) { fullQuery.add("content.visible=" + getNativeSQLExpression(NATIVESQL_BOOLEAN_TRUE)); fullQuery.add("(content.validfrom is null OR content.validfrom <= current_timestamp())"); fullQuery.add("(content.validto is null OR content.validto >= current_timestamp())"); String role = WGContent.DISPLAYTYPE_SEARCH; if (queryOptions.containsKey(WGDatabase.QUERYOPTION_ROLE)) { role = (String) queryOptions.get(WGDatabase.QUERYOPTION_ROLE); } if (role != null && !role.equals(WGContent.DISPLAYTYPE_NONE)) { fullQuery.add(":wgaparamRole not in elements(content.ishiddenfrom)"); queryParams.put("wgaparamRole", role); } } if (queryOptions.containsKey(WGDatabase.QUERYOPTION_ONLYRELEASED)) { fullQuery.add("content.status = 'p'"); } // Filter languages if (queryOptions.containsKey(WGDatabase.QUERYOPTION_LANGUAGES)) { List<WGLanguage> langs = (List<WGLanguage>) queryOptions.get(WGDatabase.QUERYOPTION_LANGUAGES); if (langs.size() > 1 && lazyFetch) { List languageTerms = new ArrayList(); for (WGLanguage lang : langs) { languageTerms.add("content.language.name = '" + lang.getName() + "'"); } fullQuery.add("(" + WGUtils.serializeCollection(languageTerms, " OR ") + ")"); languagesPriorityList = langs; } else if (langs.size() == 1) { fullQuery.add("content.language.name = :wgaparamLanguage"); queryParams.put("wgaparamLanguage", langs.get(0).getName()); } else { fullQuery.add("content.language.name = :wgaparamLanguage"); queryParams.put("wgaparamLanguage", getDb().getDefaultLanguage()); } } else if (queryOptions.containsKey(WGDatabase.QUERYOPTION_ONLYLANGUAGE)) { fullQuery.add("content.language.name = '" + queryOptions.get(WGDatabase.QUERYOPTION_ONLYLANGUAGE).toString() + "'"); } // Filter the "current document" if (queryOptions.containsKey(WGDatabase.QUERYOPTION_EXCLUDEDOCUMENT)) { WGContent content = (WGContent) queryOptions.get(WGDatabase.QUERYOPTION_EXCLUDEDOCUMENT); if (content.getDatabase() == this._db && !content.isDummy() && content.isSaved()) { WGDocumentCore contentCore = content.getCore(); if (contentCore instanceof WGDocumentImpl) { Content contentEntity = (Content) ((WGDocumentImpl) content.getCore()).getEntity(); if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { fullQuery.add("not content.id = :wgaparamEntityId"); queryParams.put("wgaparamEntityId", contentEntity.getId()); } else { fullQuery.add("not content.cuid = :wgaparamEntityId"); queryParams.put("wgaparamEntityId", contentEntity.getCuid()); } } } } // Extract ORDER BY part to get it out of the brackets String furtherClauses = ""; int whereClauseEndIdx = query.toLowerCase().indexOf("group by"); if (whereClauseEndIdx == -1) { whereClauseEndIdx = query.toLowerCase().indexOf("order by"); } if (whereClauseEndIdx != -1) { furtherClauses = query.substring(whereClauseEndIdx); query = query.substring(0, whereClauseEndIdx); } fullQuery.add("(" + query + ")"); builtQuery = composeHQLQuery(fullQuery, furtherClauses, lazyFetch, (languagesPriorityList != null)); } if (builtQuery == null) { throw new WGQueryException(query, "Unknown query type: " + type); } builtQuery = WGUtils.strReplace(builtQuery, "\"", "'", true); if (queryOptions != null) { queryOptions.put(WGDatabase.QUERYOPTION_RETURNQUERY, builtQuery); } List results = null; try { Query hibQuery = getSession().createQuery(builtQuery); int maxResults = 0; if (queryOptions.containsKey(WGDatabase.QUERYOPTION_MAXRESULTS)) { maxResults = ((Number) queryOptions.get(WGDatabase.QUERYOPTION_MAXRESULTS)).intValue(); } if (maxResults > 0) { hibQuery.setMaxResults(maxResults); } HibernateResultSet.injectQueryParams(hibQuery, queryParams); if (lazyFetch) { if (languagesPriorityList != null) { return new WGLanguageChoosingHQLResultSet(this, hibQuery, queryParams, queryOptions, languagesPriorityList); } else { return new WGLazyHQLResultSet(this, hibQuery, queryParams, queryOptions); } } else { return new WGStraightHQLResultSet(this, hibQuery, queryParams, queryOptions); } } catch (QueryException e) { throw new WGQueryException(builtQuery, e.getMessage(), e); } catch (HibernateException e) { throw new WGBackendException("Error executing HQL query", e); } } protected String getNativeSQLExpression(String expression) { if (NATIVESQL_BOOLEAN_TRUE.equals(expression)) { return "1"; } else { return ""; } } protected String composeHQLQuery(List fullQuery, String orderBy, boolean lazy, boolean languageChoosing) { if (lazy) { if (_hqlLazyParentCheck && !languageChoosing) { return HQLQUERY_LAZY_PARENTCHECK + WGUtils.serializeCollection(fullQuery, " and ") + " " + orderBy; } else { return HQLQUERY_LAZY + WGUtils.serializeCollection(fullQuery, " and ") + " " + orderBy; } } else { return HQLQUERY_STRAIGHT + WGUtils.serializeCollection(fullQuery, " and ") + " " + orderBy; } } public static Class getClassByType(int type) { return (Class) _typeToObject.get(new Integer(type)); } public static int getTypeByClass(Class aClass) { return ((Integer) _objectToType.get(aClass)).intValue(); } public Object getEntity(WGDocument doc) throws WGAPIException { return ((WGDocumentImpl) doc.getCore()).getEntity(); } /* * (Kein Javadoc) * * @see de.innovationgate.webgate.api.WGDatabaseCore#beginTransaction() */ public boolean beginTransaction() throws WGAPIException { Transaction transaction = getSession().getTransaction(); if (transaction != null && transaction.isActive()) { transaction.rollback(); } transaction = getSession().beginTransaction(); if (transaction != null) { getSession().setCacheMode(CacheMode.GET); _db.getSessionContext().setTransactionMode(WGSessionContext.TRANSACTION_MODE_MANUAL); return true; } else { return false; } } /* * (Kein Javadoc) * * @see de.innovationgate.webgate.api.WGDatabaseCore#commitTransaction() */ public boolean commitTransaction() throws WGAPIException { Transaction transaction = getSession().getTransaction(); if (transaction != null) { transaction.commit(); getSession().setCacheMode(CacheMode.NORMAL); _db.getSessionContext().resetTransactionMode(); getSession().beginTransaction(); return true; } return false; } public void beginUpdate() throws WGAPIException { try { getSession().getTransaction().rollback(); getSession().doWork(new Work() { public void execute(Connection connection) throws SQLException { if (connection.isReadOnly()) { connection.setReadOnly(false); } } }); String user = _db.getSessionContext().getUser(); DBUpdate update = new DBUpdate(_db.getSessionContext()); _dbUpdatesByUser.put(user, update); getSession().beginTransaction(); } catch (HibernateException e) { throw new WGBackendException("unable to start transaction", e); } } /** * checks if an update is in progress for the current session context * * @return */ private boolean isUpdateInProgress() { if (_db.getSessionContext() != null) { return isUpdateInProgress(_db.getSessionContext().getUser()); } else { return false; } } /** * checks if an update is in progress for the given user * * @param user * @return */ private boolean isUpdateInProgress(String user) { DBUpdate update = (DBUpdate) _dbUpdatesByUser.get(user); if (update != null) { return update.isInProgress(); } else { return false; } } /* * (Kein Javadoc) * * @see de.innovationgate.webgate.api.WGDatabaseCore#rollbackTransaction() */ public boolean rollbackTransaction() throws WGAPIException { Transaction transaction = getSession().getTransaction(); if (transaction != null && transaction.isActive()) { transaction.rollback(); getSession().setCacheMode(CacheMode.NORMAL); _db.getSessionContext().resetTransactionMode(); getSession().beginTransaction(); return true; } return false; } /* * (Kein Javadoc) * * @see * de.innovationgate.webgate.api.WGDatabaseCore#execProcedure(java.lang. * String, java.util.List) */ public Object execProcedure(String procName, List args) throws WGProcedureException { throw new WGProcedureException("Procedures are not yet supported"); } /* * (Kein Javadoc) * * @see de.innovationgate.webgate.api.WGDatabaseCore#getServerName() */ public String getServerName() throws WGAPIException { try { DatabaseMetaData metaData = getSession().doReturningWork(new ReturningWork<DatabaseMetaData>() { public DatabaseMetaData execute(Connection connection) throws SQLException { return connection.getMetaData(); } }); return metaData.getDatabaseProductName() + " " + metaData.getDatabaseProductVersion(); } catch (HibernateException e) { throw new WGBackendException("Error retrieving server name", e); } catch (SQLException e) { throw new WGBackendException("Error retrieving server name", e); } } /* * (Kein Javadoc) * * @see de.innovationgate.webgate.api.WGDatabaseCore#getACL() */ public WGACLCore getACL() { return _aclImpl; } public LogEntry createLogEntry(Session session, int logType, String docKey, String entityID) throws HibernateException, WGAPIException { LogEntry entry = new LogEntry(new Date(), logType, docKey.toString(), _db.getSessionContext().getUser()); entry.setTarget_id(entityID); if (_db.getContentStoreVersion() >= WGDatabase.CSVERSION_WGA5) { entry.setOperation(_db.getSessionContext().getTask()); } session.save(entry); return entry; } /* * (Kein Javadoc) * * @see * de.innovationgate.webgate.api.WGDatabaseEventListener#databaseUpdate( * de.innovationgate.webgate.api.WGDatabaseEvent) */ public void refresh() throws WGAPIException { Session session = getSession(); session.flush(); session.clear(); } /* * (Kein Javadoc) * * @see de.innovationgate.webgate.api.WGDatabaseEventListener#isTemporary() */ public boolean isTemporary() { return false; } /* * (Kein Javadoc) * * @see de.innovationgate.webgate.api.WGDatabaseCore#getNativeObject() */ public Object getNativeObject() throws WGAPIException { return getSession(); } /* * (Kein Javadoc) * * @see * de.innovationgate.webgate.api.WGDatabaseCore#resultIsFalse(java.lang. * Object, de.innovationgate.webgate.api.WGDocument) */ public boolean resultIsFalse(Object result, WGDocument doc) { return false; } /* * (Kein Javadoc) * * @see * de.innovationgate.webgate.api.WGDatabaseCore#resultIsTrue(java.lang.Object * , de.innovationgate.webgate.api.WGDocument) */ public boolean resultIsTrue(Object result, WGDocument doc) { return false; } /** * @param props */ public static void putDefaultConPoolProps(WGDatabase db, Properties props) { if (db != null) { if (db.hasFeature(WGDatabase.FEATURE_LOADBALANCE)) { WGUtils.setDefaultProperty(props, "hibernate.connection.provider_class", DBCPReplicationConnectionProvider.class.getName()); } else { WGUtils.setDefaultProperty(props, "hibernate.connection.provider_class", DBCPConnectionProvider.class.getName()); } } WGUtils.setDefaultProperty(props, "hibernate.dbcp.maxActive", "100"); WGUtils.setDefaultProperty(props, "hibernate.dbcp.whenExhaustedAction", "1"); WGUtils.setDefaultProperty(props, "hibernate.dbcp.maxWait", "120000"); WGUtils.setDefaultProperty(props, "hibernate.dbcp.maxIdle", "10"); WGUtils.setDefaultProperty(props, "hibernate.dbcp.poolPreparedStatements", "true"); WGUtils.setDefaultProperty(props, "hibernate.dbcp.maxOpenPreparedStatements", DEFAULT_MAXOPENPREPAREDSTATEMENTS); //WGUtils.setDefaultProperty(props, "hibernate.dbcp.maxConnLifetimeMillis", String.valueOf(MySqlDatabaseServer.DEFAULT_SHAREDPOOL_MAX_CONNECTION_LIFETIME)); WGUtils.setDefaultProperty(props, "hibernate.dbcp.legacyJMX", String .valueOf("true".equals(db.getCreationOptions().get(WGDatabase.COPTION_LEGACY_DBCP_MONITORING)))); if (db != null && db.getDbReference().indexOf(":") == -1) { props.put("hibernate.dbcp.dbkey", db.getDbReference()); } } public static void putDefaultServerConPoolProps(WGDatabaseServer server, Properties props) { WGUtils.setDefaultProperty(props, "hibernate.dbcp.timeBetweenEvictionRunsMillis", String.valueOf(1000 * 60)); WGUtils.setDefaultProperty(props, "hibernate.dbcp.minEvictableIdleTimeMillis", String.valueOf(1000 * 60)); WGUtils.setDefaultProperty(props, "hibernate.dbcp.numTestsPerEvictionRun", String.valueOf(10)); WGUtils.setDefaultProperty(props, "hibernate.dbcp.whenExhaustedAction", "1"); WGUtils.setDefaultProperty(props, "hibernate.dbcp.maxWait", "120000"); WGUtils.setDefaultProperty(props, "hibernate.dbcp.poolPreparedStatements", "true"); WGUtils.setDefaultProperty(props, "hibernate.dbcp.maxOpenPreparedStatements", DEFAULT_MAXOPENPREPAREDSTATEMENTS); WGUtils.setDefaultProperty(props, "hibernate.dbcp.removeAbandoned", "true"); WGUtils.setDefaultProperty(props, "hibernate.dbcp.removeAbandonedTimeout", String.valueOf(60 * 60 * 24)); WGUtils.setDefaultProperty(props, "hibernate.dbcp.legacyJMX", String.valueOf( "true".equals(server.getOptions().get(DatabaseServer.OPTION_SHAREDPOOL_LEGACY_DBCP_MONITORING)))); } /* * (Kein Javadoc) * * @see * de.innovationgate.webgate.api.WGDatabaseCore#getUpdatedDocumentsSince * (java.util.Date) */ public List<WGUpdateLog> getUpdateLogs(Comparable fromRevision) throws WGAPIException { try { Iterator logEntries; if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { Query logEntriesQ = getSession().createQuery( "from de.innovationgate.webgate.api.jdbc.LogEntry as logentry where id > :start order by id asc"); logEntriesQ.setLong("start", ((Long) fromRevision).longValue()); logEntries = logEntriesQ.iterate(); } else { Date cutoff = (Date) fromRevision; Query logEntriesQ = getSession().createQuery( "from de.innovationgate.webgate.api.jdbc.LogEntry as logentry where logtime >= :start order by logtime asc"); logEntriesQ.setTimestamp("start", new java.sql.Timestamp(cutoff.getTime())); logEntries = logEntriesQ.iterate(); } List wgLogs = new ArrayList(); LinkedMap wgLogsByTarget = new LinkedMap(); Map conflictTargets = new HashMap(); LogEntry entry; // First pass: Create update logs while (logEntries.hasNext()) { entry = (LogEntry) logEntries.next(); WGUpdateLog newLog = null; WGUpdateLog oldLog = null; Date currentTime = null; if (entry.getTarget() != null && !entry.getTarget().equals("#UNKNOWN#")) { newLog = readUpdateLog(entry); wgLogs.add(newLog); List logsList = (List) wgLogsByTarget.get(entry.getTarget()); if (logsList == null) { logsList = new ArrayList(); wgLogsByTarget.put(entry.getTarget(), logsList); } logsList.add(newLog); } } // Second pass for CS version < 5 to workaround some weaknesses of the CS3/4 history log if (_ddlVersion < WGDatabase.CSVERSION_WGA5) { // Determine conflicting log entries, where update and delete is done on the same time and the same document Iterator wgLogsByTargetIt = wgLogsByTarget.values().iterator(); while (wgLogsByTargetIt.hasNext()) { List logs = (List) wgLogsByTargetIt.next(); WGUtils.sortByProperty(logs, "date"); Iterator logsIt = logs.iterator(); Date lastTime = null; List<WGUpdateLog> logsAtSameTime = new ArrayList(); while (logsIt.hasNext()) { WGUpdateLog log = (WGUpdateLog) logsIt.next(); if (log.getDate().equals(lastTime)) { logsAtSameTime.add(log); } else { resolveLogConflicts(wgLogs, logsAtSameTime); logsAtSameTime.clear(); } lastTime = log.getDate(); } } // Order logentries that have the same time in an order that assures dependency documents are created before their dependent documents Collections.sort(wgLogs, new DocumentDependencyComparator()); } return wgLogs; } catch (HibernateException e) { throw new WGBackendException("Unable to retrieve updated documents", e); } } protected WGUpdateLog readUpdateLog(LogEntry entry) { return new WGUpdateLog(entry.getType(), entry.getLogtime(), entry.getLoguser(), entry.getTarget(), entry.getOperation(), getLogRevision(entry)); } private void resolveLogConflicts(List wgLogs, List conflictLogs) { // Reverse the sort order so we have the maximum logtimes at the beginning Collections.reverse(conflictLogs); // Get the operations having the maximum logtime WGUpdateLog maxUpdateLog = null; WGUpdateLog maxDeletionLog = null; Iterator logsIt = conflictLogs.iterator(); Date maxDate = null; while (logsIt.hasNext()) { WGUpdateLog log = (WGUpdateLog) logsIt.next(); if (maxDate == null) { maxDate = log.getDate(); } else if (!maxDate.equals(log.getDate())) { break; } if (log.getType() == WGUpdateLog.TYPE_UPDATE) { maxUpdateLog = log; } else if (log.getType() == WGUpdateLog.TYPE_DELETE) { maxDeletionLog = log; } } // Now lets see what we have - If there is only one type of log we have no problem if (maxDeletionLog != null && maxUpdateLog == null) { } else if (maxUpdateLog != null && maxDeletionLog == null) { } else if (maxUpdateLog != null && maxDeletionLog != null) { // So we have an update and a deletion at the same time. // We cannot determine by log which was before the other. // Therefor we look if the document exists. // If so we use the update log, else the deletion log. // The nonused log is therefor removed from the log list WGDocument doc = null; WGDocumentKey documentKey = new WGDocumentKey(maxUpdateLog.getDocumentKey()); if (documentKey.isRealDocumentKey()) { try { doc = _db.getDocumentByKey(documentKey); if (doc != null && !doc.isDeleted()) { WGFactory.getLogger().info("Resolving log conflict about document " + maxUpdateLog.getDocumentKey() + ": Relevant log type determined as update"); wgLogs.remove(maxDeletionLog); } else { WGFactory.getLogger().info("Resolving log conflict about document " + maxUpdateLog.getDocumentKey() + ": Relevant log type determined as deletion"); wgLogs.remove(maxUpdateLog); } } catch (WGAPIException e) { WGFactory.getLogger().error( "Exception resolving log conflict for document " + maxUpdateLog.getDocumentKey(), e); } } } } public WGDocumentImpl createDocumentImpl(MainEntity entity) { int type; if (entity instanceof Content) { type = WGDocument.TYPE_CONTENT; } else if (entity instanceof StructEntry) { type = WGDocument.TYPE_STRUCTENTRY; } else if (entity instanceof Area) { type = WGDocument.TYPE_AREA; } else if (entity instanceof ContentType) { type = WGDocument.TYPE_CONTENTTYPE; } else if (entity instanceof TMLModule) { type = WGDocument.TYPE_TML; } else if (entity instanceof CSSJSModule) { type = WGDocument.TYPE_CSSJS; } else if (entity instanceof Language) { type = WGDocument.TYPE_LANGUAGE; } else if (entity instanceof UserProfile) { type = WGDocument.TYPE_USERPROFILE; } else if (entity instanceof FileContainer) { type = WGDocument.TYPE_FILECONTAINER; } else { throw new IllegalArgumentException( "The given object type is no known entity: " + entity.getClass().getName()); } return new WGDocumentImpl(this, entity, type); } /* * (non-Javadoc) * * @seede.innovationgate.webgate.api.WGDatabaseCore#moveStructEntry(de. * innovationgate.webgate.api.WGStructEntry, * de.innovationgate.webgate.api.WGDocument) */ public boolean moveStructEntry(WGStructEntry entry, WGDocument newParent) { try { WGDocumentImpl docCore = (WGDocumentImpl) entry.getCore(); docCore.makeEditable(); StructEntry structEntry = (StructEntry) docCore.getEntity(); // Remove from former parent object // Manual initializings are workaround for hibernate bug B00005D36 StructEntry parentEntry = structEntry.getParententry(); if (parentEntry != null) { if (_ddlVersion < WGDatabase.CSVERSION_WGA5) { Hibernate.initialize(parentEntry.getChildentries()); StructEntry oldEntry = (StructEntry) parentEntry.getChildentries().remove(structEntry.getKey()); if (oldEntry != null && _saveIsolationActive) { getSession().evict(oldEntry); } } } else { Area area = structEntry.getArea(); if (_ddlVersion < WGDatabase.CSVERSION_WGA5) { Hibernate.initialize(area.getRootentries()); StructEntry oldEntry = (StructEntry) area.getRootentries().remove(structEntry.getKey()); if (oldEntry != null && _saveIsolationActive) { getSession().evict(oldEntry); } } } // Set to new parent object if (newParent instanceof WGArea) { Area area = (Area) newParent.getNativeObject(); structEntry.setParententry(null); structEntry.setArea(area); if (_ddlVersion < WGDatabase.CSVERSION_WGA5) { area.getRootentries().put(structEntry.getKey(), structEntry); } } else if (newParent instanceof WGStructEntry) { StructEntry parent = (StructEntry) newParent.getNativeObject(); structEntry.setParententry(parent); structEntry.setArea(null); if (_ddlVersion < WGDatabase.CSVERSION_WGA5) { parent.getChildentries().put(structEntry.getKey(), structEntry); } } else { return false; } createLogEntry(getSession(), WGUpdateLog.TYPE_STRUCTMOVE, entry.getDocumentKey(), structEntry.getId()); entry.save(); return true; } catch (WGAPIException e) { WGFactory.getLogger().error("Error moving struct entry", e); e.printStackTrace(); return false; } } public int getContentCount(WGStructEntry structEntry) throws WGAPIException { try { Query query; if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { query = getSession() .createQuery("select id from Content as content where content.structentry.key=:key"); } else { query = getSession() .createQuery("select cuid from Content as content where content.structentry.key=:key"); } query.setParameter("key", String.valueOf(structEntry.getStructKey())); return query.list().size(); } catch (HibernateException e) { throw new WGBackendException("Error determining content presence for " + structEntry.getDocumentKey(), e); } } /* * (non-Javadoc) * * @seede.innovationgate.webgate.api.WGDatabaseCore#setCurrentSession(de. * innovationgate.webgate.api.WGSessionContext) */ public void setCurrentSession(WGSessionContext context) { } public String convertFileNameForAttaching(String name) { return WGUtils.strReplace(name.toLowerCase(), "", "/", true); } public void authenticationDataChanged() { _db.getUserCache().clear(); } /* * (non-Javadoc) * * @see * de.innovationgate.webgate.api.WGDatabaseCore#getAllowedCredentialClasses * () */ public Class[] getAllowedCredentialClasses() { return null; } public List queryUserProfileNames(String type, String query, Map params) throws WGAPIException { if (type == null) { type = "hql"; } try { String fullQuery; if (query != null) { if (type.equals("hql")) { fullQuery = "select profile.name from UserProfile profile where (" + query + ") order by profile.name asc"; } else if (type.equals("fullhql")) { fullQuery = query; } else { throw new WGQueryException(query, "Unknown query type '" + type + "'"); } } else { fullQuery = "select profile.name from UserProfile profile order by profile.name asc"; } Query hqlQuery = getSession().createQuery(fullQuery); if (params.containsKey(WGDatabase.QUERYOPTION_MAXRESULTS)) { Number maxResults = (Number) params.get(WGDatabase.QUERYOPTION_MAXRESULTS); hqlQuery.setMaxResults(maxResults.intValue()); } return hqlQuery.list(); } catch (QueryException e) { throw new WGQueryException(query, e.getMessage(), e); } catch (HibernateException e) { throw new WGBackendException("Error executing profile query", e); } } public void commitHibernateTransaction() throws WGAPIException { if (getTransactionMode() != WGSessionContext.TRANSACTION_MODE_MANUAL) { Transaction trans = getSession().getTransaction(); if (trans != null) { trans.commit(); } // hibernate might release the underlying jdbc connection after commit // and get a new one // this connection will be readonly by default - therefore we should // check if we have to // make it read/write if (isUpdateInProgress()) { try { getSession().doWork(new Work() { public void execute(Connection connection) throws SQLException { if (connection.isReadOnly()) { connection.setReadOnly(false); } } }); } catch (HibernateException e) { throw new WGBackendException("unable to establish a read/write connection.", e); } } getSession().beginTransaction(); } else { // perform at least a flush in this mode so JDBC driver will execute changes in current JDBC transaction getSession().flush(); } } protected void rollbackHibernateTransaction(boolean noThrows) throws WGAPIException { if (getTransactionMode() != WGSessionContext.TRANSACTION_MODE_MANUAL) { try { Transaction trans = getSession().getTransaction(); if (trans != null && trans.isActive()) { trans.rollback(); } // hibernate might release the underlying jdbc connection after commit // and get a new one // this connection will be readonly by default - therefore we should // check if we have to // make it read/write if (isUpdateInProgress()) { try { getSession().doWork(new Work() { public void execute(Connection connection) throws SQLException { if (connection.isReadOnly()) { connection.setReadOnly(false); } } }); } catch (HibernateException e) { throw new WGBackendException("unable to establish a read/write connection.", e); } } getSession().beginTransaction(); } catch (Throwable e) { if (noThrows) { WGFactory.getLogger().error( "Exception rolling back transaction. Cause for rollback may be logged after this exception.", e); } else if (e instanceof WGBackendException) { throw (WGBackendException) e; } else if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { throw new WGBackendException("Exception rolling back transaction", e); } } } } /* * (non-Javadoc) * * @see * de.innovationgate.webgate.api.WGDatabaseCore#getDeletions(java.util.Set) */ public Set getDeletions(Set contentKeys) throws WGAPIException { // unsupported for this implementation return Collections.EMPTY_SET; } public List getAllContentKeys(boolean includeArchived) throws WGAPIException { try { String hql = "select new de.innovationgate.webgate.api.WGContentKey(content.structentry.key, content.language.name, content.version) from Content as content"; if (!includeArchived) { hql += " where not content.status='" + WGContent.STATUS_ARCHIVE + "'"; } Query query = getSession().createQuery(hql); return new ArrayList(query.list()); } catch (HibernateException e) { throw new WGBackendException("Exception retrieving all content keys", e); } } public WGDatabase getDb() { return _db; } protected SessionStatus getSessionStatus() { SessionStatus ss = (SessionStatus) _sessionStatus.get(); if (ss == null) { ss = new SessionStatus(); _sessionStatus.set(ss); } return ss; } public boolean isHqlLazyByDefault() { return _hqlLazyByDefault; } public void setHqlLazyByDefault(boolean hqlLazyByDefault) { _hqlLazyByDefault = hqlLazyByDefault; } public boolean useOptimizedFileHandling() throws WGAPIException { return _db.getContentStoreVersion() >= WGDatabase.CSVERSION_WGA4_1; } protected void updateContentRelations(Content content) throws WGAPIException { if (_ddlVersion < WGDatabase.CSVERSION_WGA5) { return; } Query query = getSession().createQuery(HQLQUERY_UPDATE_RELATIONS); query.setParameter("target", content); query.setParameter("structentry", content.getStructentry().getKey()); query.setParameter("language", content.getLanguage().getName()); query.executeUpdate(); } public WGDocumentCore getStructEntryByName(String strName) throws WGAPIException { Query query = getSession().createQuery(HQLQUERY_GET_STRUCT_BY_NAME); query.setParameter("name", strName); Iterator results = query.iterate(); if (results.hasNext()) { StructEntry entry = (StructEntry) results.next(); return createDocumentImpl(entry); } else { return null; } } public Date getRevisionDate(Comparable lastChanged) throws WGAPIException, WGWrongRevisionException { if (_ddlVersion >= WGDatabase.CSVERSION_WGA5) { if (!(lastChanged instanceof Long)) { throw new WGWrongRevisionException(Long.class); } LogEntry entry = (LogEntry) getSession().get(LogEntry.class, (Long) lastChanged); if (entry != null) { return entry.getLogtime(); } else { return null; //return new Date(Long.MIN_VALUE); } } else { try { return (Date) lastChanged; } catch (ClassCastException e) { throw new WGWrongRevisionException(Date.class); } } } public double getContentStoreVersion() throws WGAPIException { return _csVersion.getVersion(); } @Override public int getContentStorePatchLevel() throws WGAPIException { return _csVersion.getPatchLevel(); } public void writeExtensionData(String name, Object value) throws WGAPIException { name = name.toLowerCase().trim(); // Convert numbers to doubles if (value instanceof Number && !(value instanceof Double)) { value = new Double(((Number) value).doubleValue()); } try { ExtensionData md = retrieveExtensionData(name); if (md == null) { md = new ExtensionData(); md.setName(name); WGDocumentImpl.writeItemValue(this, null, md, value); getSession().save(md); } else { if (_saveIsolationActive) { getSession().evict(md); } WGDocumentImpl.writeItemValue(this, null, md, value); if (_saveIsolationActive) { getSession().update(md); } } createLogEntry(getSession(), WGUpdateLog.TYPE_UPDATE, WGDocument.TYPENAME_DBMETADATA + "/" + name, md.getId()); commitHibernateTransaction(); } catch (HibernateException e) { throw new WGBackendException("Error setting database metadata.", e); } } public void removeExtensionData(String name) throws WGAPIException { name = name.toLowerCase().trim(); ExtensionData md = retrieveExtensionData(name); if (md != null) { String mdId = md.getId(); getSession().delete(md); createLogEntry(getSession(), WGUpdateLog.TYPE_DELETE, WGDocument.TYPENAME_DBMETADATA + "/" + name, mdId); commitHibernateTransaction(); } } public List<String> getExtensionDataNames() throws WGAPIException { return getSession().createQuery("select name from ExtensionData where entity = null").list(); } public List<WGRelationData> getIncomingRelations(Object structKey, String language, String contentClass, String relName, String relGroupName, Boolean includeUnreleased, WGColumnSet order) throws WGAPIException { if (_ddlVersion < WGDatabase.CSVERSION_WGA5) { return Collections.emptyList(); } StringBuffer hql = new StringBuffer( "select relation from ContentRelation as relation where relation.targetstructentry = :structkey and relation.targetlanguage = :language and relation.parentcontent.status in (:states)"); Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put("structkey", structKey); parameters.put("language", language); if (relName != null) { hql.append(" and relation.name = :relname"); parameters.put("relname", relName); } if (relGroupName != null) { hql.append(" and relation.group = :relgroup"); parameters.put("relgroup", relGroupName); } if (contentClass != null) { hql.append(" and relation.parentcontent.contentclass = :sourceclass"); parameters.put("sourceclass", contentClass); } if (order != null) { hql.append(" order by "); hql.append(buildHqlContentOrderClause("relation.parentcontent", order, parameters)); } Query query = getSession().createQuery(hql.toString()); for (Map.Entry<String, Object> param : parameters.entrySet()) { query.setParameter(param.getKey(), param.getValue()); } if (includeUnreleased) { query.setParameterList("states", new Object[] { WGContent.STATUS_DRAFT, WGContent.STATUS_REVIEW, WGContent.STATUS_RELEASE }); } else { query.setParameterList("states", new Object[] { WGContent.STATUS_RELEASE }); } /* Criteria crit = getSession().createCriteria(ContentRelation.class); crit.add(Restrictions.eq("targetstructentry", structKey)); crit.add(Restrictions.eq("targetlanguage", language)); crit.setFetchMode("parentcontent", FetchMode.SELECT); if (includeUnreleased) { crit.createCriteria("parentcontent").add(Restrictions.in("status", new Object[] {WGContent.STATUS_DRAFT, WGContent.STATUS_REVIEW, WGContent.STATUS_RELEASE})); } else { crit.createCriteria("parentcontent").add(Restrictions.eq("status", WGContent.STATUS_RELEASE)); }*/ List<WGRelationData> incoming = new ArrayList(); for (ContentRelation rel : (List<ContentRelation>) query.list()) { WGRelationData relData = createWGRelationData(rel); incoming.add(relData); } return incoming; } protected WGRelationData createWGRelationData(ContentRelation rel) { Content content = rel.getParentcontent(); WGContentKey cKey = new WGContentKey(content.getStructentry().getKey(), content.getLanguage().getName(), content.getVersion().intValue()); WGRelationData relData = new WGRelationData(_db, cKey, rel.getName(), rel.getTargetstructentry(), rel.getTargetlanguage(), rel.getType(), rel.getGroup()); return relData; } /** * Returns if query paging for optimized file handling is enabled, see * {@link #COPTION_OPTIMIZED_FILE_HANDLING_DISABLEQUERYPAGING} */ public boolean isOptimizedFileHandlingDisableQueryPaging() { Object disableQueryPaging = _db.getCreationOptions() .get(COPTION_OPTIMIZED_FILE_HANDLING_DISABLEQUERYPAGING); if (disableQueryPaging != null) { return Boolean.valueOf((String) disableQueryPaging).booleanValue(); } else { return true; } } public boolean isContentTypeUsed(WGContentType ctDoc) throws WGAPIException { // Get the entity WGDocumentImpl docCore = (WGDocumentImpl) ctDoc.getCore(); ContentType ct = (ContentType) docCore.getEntity(); // Do a criteria query Criteria crit = getSession().createCriteria(StructEntry.class); crit.add(Restrictions.eq("contenttype", ct)); crit.setMaxResults(1); List docs = crit.list(); return docs.size() > 0; } public boolean isLanguageUsed(WGLanguage langDoc) throws WGAPIException { // Get the entity WGDocumentImpl docCore = (WGDocumentImpl) langDoc.getCore(); Language lang = (Language) docCore.getEntity(); // Do a criteria query Criteria crit = getSession().createCriteria(Content.class); crit.add(Restrictions.eq("language", lang)); crit.setMaxResults(1); List docs = crit.list(); return docs.size() > 0; } public Iterator<String> getAllUserProfileNames() throws WGAPIException { try { String fullQuery = "select profile.name from UserProfile profile order by profile.name asc"; Query hqlQuery = getSession().createQuery(fullQuery); return hqlQuery.iterate(); } catch (QueryException e) { throw new WGQueryException("Querying all user profile names", e.getMessage(), e); } catch (HibernateException e) { throw new WGBackendException("Error executing profile query", e); } } public boolean isBackendServiceSupported(String serviceName) { if (WGDatabase.BACKENDSERVICE_SELECT_PENDINGRELEASE_DOCS.equals(serviceName)) { return true; } else if (WGDatabase.BACKENDSERVICE_DAILY_MAINTENANCE.equals(serviceName)) { return (_fileHandling instanceof CS5P4FileHandling); } else if (BACKENDSERVICE_UPGRADE_FILE_STORAGE.equals(serviceName)) { return (_fileHandling instanceof CS5P4FileHandling); } else if (WGDatabase.BACKENDSERVICE_NEW_CONTENT_VERSION.equals(serviceName)) { return true; } else if (WGDatabase.BACKENDSERVICE_PROBE_CONTENT.equals(serviceName)) { return true; } else if (WGDatabase.BACKENDSERVICE_FETCH_MULTI_CONTENT.equals(serviceName)) { return true; } return false; } public Object callBackendService(String serviceName, Object[] params) throws WGAPIException { if (WGDatabase.BACKENDSERVICE_SELECT_PENDINGRELEASE_DOCS.equals(serviceName)) { String query; if (getContentStoreVersion() >= WGDatabase.CSVERSION_WGA5) { query = HQLQUERY_PENDING_RELEASE_DOCS_CS5; } else { query = HQLQUERY_PENDING_RELEASE_DOCS_CS3; } Map queryParams = new HashMap(); queryParams.put(WGDatabase.QUERYOPTION_ENHANCE, false); return _db.query("hql", query, queryParams); } else if (WGDatabase.BACKENDSERVICE_DAILY_MAINTENANCE.equals(serviceName)) { if (_ugradeFileStorageRunning) { return null; } dailyMaintenance(params.length >= 1 ? (Logger) params[0] : WGFactory.getLogger()); return null; } else if (BACKENDSERVICE_UPGRADE_FILE_STORAGE.equals(serviceName)) { return upgradeFileStorage((Logger) params[0]); } else if (WGDatabase.BACKENDSERVICE_NEW_CONTENT_VERSION.equals(serviceName)) { return newContentVersion((WGStructEntry) params[0], (WGLanguage) params[1]); } else if (WGDatabase.BACKENDSERVICE_PROBE_CONTENT.equals(serviceName)) { return probeContent((WGStructEntry) params[0], (String) params[1], (String) params[2]); } else if (WGDatabase.BACKENDSERVICE_FETCH_MULTI_CONTENT.equals(serviceName)) { return fetchMultiContent((List<String>) params[0]); } else { throw new WGNotSupportedException("Backend service not supported: " + serviceName); } } private WGResultSetCore fetchMultiContent(List<String> keys) throws WGAPIException { String hql = "select content from Content as content where concat(content.structentry.key, '.', content.language.name, '.', content.version) in (:keys)"; Map<String, Object> options = new HashMap<String, Object>(); options.put(WGDatabase.QUERYOPTION_ENHANCE, false); options.put(WGDatabase.QUERYOPTION_NATIVEOPTIONS, "straight"); options.put(WGDatabase.QUERYOPTION_MAXRESULTS, 0); options.put(WGDatabase.QUERYOPTION_ROLE, "none"); Map<String, Object> params = new HashMap<String, Object>(); params.put("keys", keys); options.put(WGDatabase.QUERYOPTION_QUERY_PARAMETERS, params); return query("fullhql", hql, options); } private boolean probeContent(WGStructEntry page, String language, String status) throws WGAPIException { StringBuffer hql = new StringBuffer(); hql.append("select count(*) from Content as content where content.structentry.key=:page"); if (language != null) { hql.append(" and content.language.name=:lang"); } if (status != null) { hql.append(" and content.status=:status"); } Query q = getSession().createQuery(hql.toString()); q.setParameter("page", page.getStructKey()); if (language != null) { q.setParameter("lang", language); } if (status != null) { q.setParameter("status", status); } Number count = (Number) q.uniqueResult(); return (count != null && count.intValue() > 0); } private int newContentVersion(WGStructEntry structEntry, WGLanguage lang) throws WGAPIException { String hql = "select max(content.version) from Content as content where content.structentry.key=:key and content.language.name=:lang"; Query q = getSession().createQuery(hql); q.setParameter("key", structEntry.getStructKey()); q.setParameter("lang", lang.getName()); Iterator it = q.iterate(); Number maxVersion = null; if (it.hasNext()) { maxVersion = (Number) it.next(); } if (maxVersion == null) { maxVersion = 0; } return maxVersion.intValue() + 1; } private Long upgradeFileStorage(Logger log) throws WGAPIException { _ugradeFileStorageRunning = true; try { if (_csVersion.getVersion() < 5.0 || _csVersion.getPatchLevel() < 4) { log.error("This task needs a content store of version 5.0 patch level 4 or higher"); return 0L; } CS5P4FileHandling fileHandling = ((CS5P4FileHandling) _fileHandling); long freedMemory = 0; while (true) { String metaHql = "from ContentFileMeta as meta where meta.checksumSha512 is null"; Iterator oldMetas = getSession().createQuery(metaHql).iterate(); try { int counter = 0; if (!oldMetas.hasNext()) { break; } while (oldMetas.hasNext() && counter < 100) { ContentFileMeta meta = (ContentFileMeta) oldMetas.next(); getSession().setReadOnly(meta, false); LockRequest lockRequest = getSession() .buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)); lockRequest.lock(meta); try { // Just-for-sure check if this is really not yet migrated getSession().refresh(meta); if (meta.getChecksumSha512() != null) { rollbackHibernateTransaction(false); continue; } log.info("Database: " + getDb().getDbReference() + ": Upgrading storage of file '" + meta.getName() + "' from document '" + meta.getParentcontent().getTitle() + "' (" + meta.getParentcontent().getStructentry().getKey() + "." + meta.getParentcontent().getLanguage().getName() + "." + meta.getParentcontent().getVersion() + ")"); // Select file parts String hqlQuery = "select cfp from ContentFilePart as cfp where cfp.meta=:metaEntity order by cfp.partnr asc"; Query query = getSession().createQuery(hqlQuery); query.setParameter("metaEntity", meta); // Migrate file parts to filecontents parts InputStream in = new HibernateQueryInputStream(fileHandling.getParent().getSession(), query, 0, isOptimizedFileHandlingDisableQueryPaging()); try { fileHandling.storeFileContents(meta, new CS5P4ContentFileDescriptor(), in); } finally { in.close(); } // Delete file parts Query deletionQuery = getSession() .createQuery("delete ContentFilePart cfp where cfp.meta = :meta"); deletionQuery.setEntity("meta", meta); deletionQuery.executeUpdate(); // Commit so we can read the file afterwards commitHibernateTransaction(); /* // Annotate the file WGDocumentImpl doc = createDocumentImpl(meta.getParentcontent()); TemporaryFile tempFile = new TemporaryFile(meta.getName(), doc.getFileData(meta.getName()), WGFactory.getTempDir()); try { WGFileMetaData md = new WGFileMetaData(new WGDocument.FakeMetaDataContext(), meta.getName(), meta.getSize(), meta.getCreated(), meta.getLastmodified(), meta.getChecksum(), meta.getChecksumSha512(), fileHandling.loadMdExtensionData(doc, meta)); _db.annotateMetadata(tempFile.getFile(), md, null); fileHandling.storeMdExtensionData(doc, md, meta); if (isSaveIsolationActive()) { getSession().update(meta); // This will not be able to store binary extension data, which however cannot be present before upgrading the file storage } } finally { tempFile.delete(); } commitHibernateTransaction(); */ } catch (Throwable e) { log.error("Exception upgrading file", e); rollbackHibernateTransaction(false); } counter++; } log.info("Clearing session cache"); refresh(); log.info("Running file storage maintenance to remove duplicate file data"); freedMemory += dailyMaintenance(log); } finally { Hibernate.close(oldMetas); } } log.info("Database: " + getDb().getDbReference() + ": Upgrading file storage freed " + WGUtils.DECIMALFORMAT_STANDARD.format(freedMemory / 1024 / 1024) + " MB of file storage memory."); return freedMemory; } finally { _ugradeFileStorageRunning = false; } } protected long dailyMaintenance(Logger log) throws WGAPIException { return getFileHandling().dailyFileMaintenance(log); } @Override public int getChildEntryCount(WGStructEntry structEntry) throws WGAPIException { StructEntry hentry = (StructEntry) ((WGDocumentImpl) structEntry.getCore()).getEntity(); Query query = getSession() .createQuery("select count(*) from StructEntry as struct where struct.parententry = :entry"); query.setParameter("entry", hentry); return ((Number) query.uniqueResult()).intValue(); } @Override public int getRootEntryCount(WGArea area) throws WGAPIException { Area harea = (Area) ((WGDocumentImpl) area.getCore()).getEntity(); Query query = getSession() .createQuery("select count(*) from StructEntry as struct where struct.area = :area"); query.setParameter("area", harea); return ((Number) query.uniqueResult()).intValue(); } @Override public void clearSessionCache() throws WGAPIException { Session session = getSessionStatus().getSession(); if (session != null) { session.flush(); session.clear(); } else { throw new WGClosedSessionException(); } } public boolean isSaveIsolationActive() { return _saveIsolationActive; } protected FileHandling getFileHandling() { return _fileHandling; } public CSVersion getCsVersion() { return _csVersion; } private TableGenerator getTableGenerator(String seqName, Long startValue) throws InstantiationException, IllegalAccessException { TableGenerator tg = _generatorCache.get(seqName); if (tg != null && (startValue == null || startValue.equals(tg.getInitialValue()))) { return tg; } Properties props = new Properties(); props.put(TableGenerator.TABLE_PARAM, "cs_sequences"); props.put(TableGenerator.SEGMENT_COLUMN_PARAM, "name"); props.put(TableGenerator.SEGMENT_VALUE_PARAM, seqName); props.put(TableGenerator.VALUE_COLUMN_PARAM, "value"); props.put(TableGenerator.OPT_PARAM, "none"); props.put(TableGenerator.IDENTIFIER_NORMALIZER, _conf.createMappings().getObjectNameNormalizer()); if (startValue != null) { props.put(TableGenerator.INITIAL_PARAM, startValue.intValue()); } tg = TableGenerator.class.newInstance(); Dialect dialect = ((SessionFactoryImplementor) _sessionFactory).getJdbcServices().getDialect(); tg.configure(_sessionFactory.getTypeHelper().basic(Long.class), props, dialect); _generatorCache.put(seqName, tg); return tg; } @Override public synchronized boolean initSequence(String name, final long startValue, final boolean forceInit) throws WGAPIException { final String internalName = buildInternalSequenceName(name); Sequence s = (Sequence) getSession().get(Sequence.class, internalName); if (!forceInit && s != null) { return false; } try { deleteSequence(name); if (startValue > 1) { getTableGenerator(internalName, startValue - 1).generate((SessionImplementor) getSession(), null); } return true; } catch (Throwable e) { throw new WGBackendException("Exception initializing sequence", e); } } public void deleteSequence(final String name) throws WGAPIException { final String internalName = buildInternalSequenceName(name); MasterSessionTask deleteSequence = new MasterSessionTask(_db) { @Override protected void exec(WGDatabase db) throws Throwable { Sequence s = (Sequence) getSession().get(Sequence.class, internalName); if (s != null) { getSession().delete(s); commitHibernateTransaction(); } } }; try { deleteSequence.runWithExceptions(); } catch (Throwable e) { throw new WGBackendException("Exception deleting sequence", e); } } @Override public long incrementSequence(String name) throws WGAPIException { final String internalName = buildInternalSequenceName(name); try { return incrementSystemSequence(internalName); } catch (Exception e) { throw new WGBackendException("Exception incrementing sequence", e); } } public long incrementSystemSequence(final String name) throws WGAPIException, InstantiationException, IllegalAccessException { return (Long) getTableGenerator(name, null).generate((SessionImplementor) getSession(), null); } public String buildInternalSequenceName(String name) throws WGIllegalDataException { if (!Constants.PATTERN_KEYS.matcher(name).matches()) { throw new WGIllegalDataException("Invalid sequence name: \"" + name + "\". Sequence names may only be alphanumeric plus the following characters: _.-:$"); } return CUSTOM_SEQUENCE_NAMEPREFIX + String.valueOf(name); } @Override public boolean isSequenceInitialized(String name) throws WGAPIException { final String internalName = buildInternalSequenceName(name); Sequence s = (Sequence) getSession().get(Sequence.class, internalName); return (s != null); } @Override public long getLastSequenceIncrementValue(String name) throws WGAPIException { final String internalName = buildInternalSequenceName(name); Sequence s = (Sequence) getSession().get(Sequence.class, internalName); if (s != null) { return s.getValue(); } else { return 0; } } @Override public List<String> getUsedSequenceNames() throws WGAPIException { Iterator i = getSession().createQuery("select seq.name from Sequence as seq").iterate(); List<String> names = new ArrayList<String>(); while (i.hasNext()) { String name = (String) i.next(); if (name.startsWith(CUSTOM_SEQUENCE_NAMEPREFIX)) { names.add(name.substring(CUSTOM_SEQUENCE_NAMEPREFIX.length())); } } return names; } protected WGDatabaseRevision getLogRevision(LogEntry logEntry) { return _ddlVersion >= WGDatabase.CSVERSION_WGA5 ? WGDatabaseRevision.forValue(logEntry.getLog_id()) : WGDatabaseRevision.forValue(logEntry.getLogtime()); } @Override public WGDocumentCore getStructEntryBySequence(long seq) throws WGAPIException { Query q = getSession().createQuery( "select struct as struct from StructEntry as struct where struct.extensionData['page-sequence'].number=:seq"); q.setParameter("seq", (double) seq); List results = q.list(); if (results.size() > 0) { Object struct = results.get(0); if (struct instanceof StructEntry) return createDocumentImpl((StructEntry) struct); } return null; } @Override public void createPageSequence(WGDocumentCore struct, boolean forceCreate) throws WGAPIException, InstantiationException, IllegalAccessException { if (struct instanceof WGDocumentImpl) ((WGDocumentImpl) struct).createPageSequence(forceCreate); } }