001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.core.impl.model.portal;
023:
024: import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
025: import org.hibernate.Query;
026: import org.hibernate.Session;
027: import org.hibernate.SessionFactory;
028: import org.hibernate.exception.ConstraintViolationException;
029: import org.jboss.logging.Logger;
030: import org.jboss.portal.core.model.portal.DuplicatePortalObjectException;
031: import org.jboss.portal.core.model.portal.PortalObjectId;
032: import org.jboss.portal.core.model.portal.PortalObjectPath;
033: import org.jboss.portal.jems.hibernate.ObjectContextualizer;
034: import org.jboss.portal.security.impl.JBossAuthorizationDomainRegistry;
035: import org.jboss.portal.security.spi.auth.PortalAuthorizationManagerFactory;
036:
037: import javax.naming.InitialContext;
038:
039: /**
040: * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
041: * @version $Revision: 9516 $
042: */
043: public class PersistentPortalObjectContainer extends
044: AbstractPortalObjectContainer {
045:
046: /** The query for lookup when the path is null. */
047: private static final String LOOKUP_QUERY_FOR_ROOT = "from ObjectNode where path=:path or path is null";
048:
049: /** The query for lookup when the path is null. */
050: private static final String LOOKUP_QUERY = "from ObjectNode where path=:path";
051:
052: /** . */
053: private static Logger log = Logger
054: .getLogger(PersistentPortalObjectContainer.class);
055:
056: /** . */
057: protected SessionFactory sessionFactory;
058:
059: /** . */
060: protected ContainerContext ctx;
061:
062: /** . */
063: protected PortalAuthorizationManagerFactory portalAuthorizationManagerFactory;
064:
065: /** . */
066: protected JBossAuthorizationDomainRegistry authorizationDomainRegistry;
067:
068: /** . */
069: protected String sessionFactoryJNDIName;
070:
071: /** . */
072: protected ObjectContextualizer contextualizer;
073:
074: /** . */
075: protected ConcurrentReaderHashMap cache;
076:
077: /** . */
078: protected boolean cacheNaturalId;
079:
080: /** . */
081: protected String rootName;
082:
083: public PersistentPortalObjectContainer() {
084: ctx = new ContainerContext() {
085: public void destroyChild(ObjectNode node) {
086: Session session = sessionFactory.getCurrentSession();
087: PortalObjectImpl object = node.getObject();
088: session.delete(object);
089: session.delete(node);
090: session.flush();
091: }
092:
093: public void createChild(ObjectNode node)
094: throws DuplicatePortalObjectException {
095: Session session = sessionFactory.getCurrentSession();
096: try {
097: session.save(node);
098: session.save(node.getObject());
099: session.flush();
100: } catch (ConstraintViolationException e) {
101: log
102: .warn("The configured database is probably case-insensitive. "
103: + e.getMessage());
104: session.close();
105: throw new DuplicatePortalObjectException();
106: }
107: }
108:
109: public void updated(ObjectNode node) {
110: Session session = sessionFactory.getCurrentSession();
111: session.flush();
112: }
113: };
114:
115: //
116: contextualizer = new ObjectContextualizer(ctx);
117: cache = new ConcurrentReaderHashMap();
118: }
119:
120: public String getRootName() {
121: return rootName;
122: }
123:
124: public void setRootName(String rootName) {
125: this .rootName = rootName;
126: }
127:
128: public void flushNaturalIdCache() {
129: cache.clear();
130: }
131:
132: public int getNaturalIdCacheSize() {
133: return cache.size();
134: }
135:
136: public boolean getCacheNaturalId() {
137: return cacheNaturalId;
138: }
139:
140: public void setCacheNaturalId(boolean cacheNaturalId) {
141: this .cacheNaturalId = cacheNaturalId;
142: }
143:
144: public JBossAuthorizationDomainRegistry getAuthorizationDomainRegistry() {
145: return authorizationDomainRegistry;
146: }
147:
148: public void setAuthorizationDomainRegistry(
149: JBossAuthorizationDomainRegistry authDomainRegistry) {
150: this .authorizationDomainRegistry = authDomainRegistry;
151: }
152:
153: public PortalAuthorizationManagerFactory getPortalAuthorizationManagerFactory() {
154: return portalAuthorizationManagerFactory;
155: }
156:
157: public void setPortalAuthorizationManagerFactory(
158: PortalAuthorizationManagerFactory pamf) {
159: this .portalAuthorizationManagerFactory = pamf;
160: }
161:
162: public void setSessionFactoryJNDIName(String sessionFactoryJNDIName) {
163: this .sessionFactoryJNDIName = sessionFactoryJNDIName;
164: }
165:
166: public ContainerContext getContainerContext() {
167: return this .ctx;
168: }
169:
170: protected void startService() throws Exception {
171: sessionFactory = (SessionFactory) new InitialContext()
172: .lookup(sessionFactoryJNDIName);
173:
174: //
175: contextualizer.attach(sessionFactory);
176:
177: // Add ourself as the authorization domain
178: if (authorizationDomainRegistry != null) {
179: authorizationDomainRegistry.addDomain(this );
180: }
181:
182: //
183: super .startService();
184: }
185:
186: protected void stopService() throws Exception {
187: super .stopService();
188:
189: //
190: if (authorizationDomainRegistry != null) {
191: authorizationDomainRegistry.removeDomain(this );
192: }
193:
194: //
195: sessionFactory = null;
196: }
197:
198: protected ContextImpl createRoot(String namespace)
199: throws DuplicatePortalObjectException {
200: log
201: .debug("Detecting the existence of the portal object root context");
202: Session session = sessionFactory.getCurrentSession();
203:
204: // Create root context if it does not exist
205: ObjectNode root = getObjectNode(session, new PortalObjectId(
206: namespace, PortalObjectPath.ROOT_PATH));
207:
208: //
209: if (root == null) {
210: // Bootstrap the root node
211: log
212: .debug("The root context of the object tree does not exist, about to create it");
213: root = new ObjectNode(this .ctx, new PortalObjectId(
214: namespace, PortalObjectPath.ROOT_PATH), namespace);
215: session.save(root);
216:
217: //
218: ContextImpl ctx = new ContextImpl();
219: root.setObject(ctx);
220: ctx.setObjectNode(root);
221: session.save(ctx);
222:
223: //
224: log
225: .info("Created portal object root context for namespace "
226: + namespace);
227:
228: //
229: return ctx;
230: } else {
231: throw new DuplicatePortalObjectException("namespace "
232: + namespace + " already exists");
233: }
234: }
235:
236: protected ObjectNode getObjectNode(PortalObjectId path) {
237: return getObjectNode(sessionFactory.getCurrentSession(), path);
238: }
239:
240: private ObjectNode getObjectNodeNoCache(Session session,
241: PortalObjectId id) {
242: Object result;
243:
244: //
245: String queryString = LOOKUP_QUERY;
246:
247: // We need to lookup the root of the empty namespace with a special query in order to fix
248: // oracle weird behavior with zero length strings considered as null value
249: if (id.getPath().getLength() == 0
250: && id.getNamespace().length() == 0) {
251: queryString = LOOKUP_QUERY_FOR_ROOT;
252: }
253:
254: //
255: Query query = session.createQuery(queryString);
256: query.setParameter("path", id);
257:
258: // Unique result will return null if no object is found
259: result = query.uniqueResult();
260:
261: return (ObjectNode) result;
262: }
263:
264: private ObjectNode getObjectNode(Session session, PortalObjectId id) {
265: // Get cached pk from natural id
266: Long pk = cacheNaturalId ? (Long) cache.get(id) : null;
267:
268: //
269: ObjectNode objectNode;
270:
271: //
272: if (pk == null) {
273: // No pk
274: objectNode = getObjectNodeNoCache(session, id);
275: } else {
276: // Try lookup using the cached pk
277: objectNode = (ObjectNode) session.get(ObjectNode.class, pk);
278:
279: // The pk may be invalid if the object has been recreted under the same path with a different pk
280: if (objectNode == null) {
281: // In that case we try a no cache
282: objectNode = getObjectNodeNoCache(session, id);
283: }
284: }
285:
286: //
287: if (cacheNaturalId) {
288: if (objectNode != null) {
289: cache.put(id, objectNode.getKey());
290: } else {
291: cache.remove(id);
292: }
293: }
294:
295: //
296: return objectNode;
297: }
298: }
|