Source Code Cross Referenced for ContentQueryManager.java in  » Web-Framework » rife-1.6.1 » com » uwyn » rife » cmf » dam » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Framework » rife 1.6.1 » com.uwyn.rife.cmf.dam 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
0003:         * Distributed under the terms of either:
0004:         * - the common development and distribution license (CDDL), v1.0; or
0005:         * - the GNU Lesser General Public License, v2.1 or later
0006:         * $Id: ContentQueryManager.java 3848 2007-07-12 08:55:48Z gbevin $
0007:         */
0008:        package com.uwyn.rife.cmf.dam;
0009:
0010:        import com.uwyn.rife.cmf.dam.exceptions.*;
0011:
0012:        import com.uwyn.rife.cmf.Content;
0013:        import com.uwyn.rife.cmf.dam.contentmanagers.DatabaseContentFactory;
0014:        import com.uwyn.rife.database.Datasource;
0015:        import com.uwyn.rife.database.DbQueryManager;
0016:        import com.uwyn.rife.database.DbTransactionUser;
0017:        import com.uwyn.rife.database.exceptions.DatabaseException;
0018:        import com.uwyn.rife.database.querymanagers.generic.GenericQueryManager;
0019:        import com.uwyn.rife.database.querymanagers.generic.GenericQueryManagerDelegate;
0020:        import com.uwyn.rife.database.querymanagers.generic.GenericQueryManagerListener;
0021:        import com.uwyn.rife.database.querymanagers.generic.RestoreQuery;
0022:        import com.uwyn.rife.engine.Element;
0023:        import com.uwyn.rife.site.Constrained;
0024:        import com.uwyn.rife.site.ConstrainedProperty;
0025:        import com.uwyn.rife.site.ConstrainedUtils;
0026:        import com.uwyn.rife.tools.BeanUtils;
0027:        import com.uwyn.rife.tools.ClassUtils;
0028:        import com.uwyn.rife.tools.ExceptionUtils;
0029:        import com.uwyn.rife.tools.InnerClassException;
0030:        import com.uwyn.rife.tools.StringUtils;
0031:        import com.uwyn.rife.tools.exceptions.BeanUtilsException;
0032:        import java.util.Collection;
0033:        import java.util.List;
0034:        import java.util.logging.Logger;
0035:
0036:        /**
0037:         * The <code>ContentQueryManager</code> simplifies working with content a lot.
0038:         * It extends {@link
0039:         * com.uwyn.rife.database.querymanagers.generic.GenericQueryManager
0040:         * GenericQueryManager} and is a drop-in replacement that can be used instead.
0041:         * The <code>ContentQueryManager</code> class works hand-in-hand with
0042:         * CMF-related constraints that are provided via the classes {@link
0043:         * com.uwyn.rife.site.Validation Validation} and {@link
0044:         * com.uwyn.rife.site.ConstrainedProperty ConstrainedProperty}. The additional constraints
0045:         * allow you to provide CMF-related metadata for bean properties while still
0046:         * having access to all regular constraints.
0047:         * <p>The most important additional constraint is '{@link
0048:         * com.uwyn.rife.site.ConstrainedProperty#mimeType(com.uwyn.rife.cmf.MimeType) mimeType}'. Setting this
0049:         * constraint directs RIFE to delegate the handling of that property's data to
0050:         * the CMF instead of storing it as a regular column in a database table. The
0051:         * property content location (i.e. its full path) is generated automatically
0052:         * based on the bean class name, the instance's identifier value (i.e. the
0053:         * primary key used by <code>GenericQueryManager</code>), and the property
0054:         * name. So for example, if you have an instance of the <code>NewsItem</code>
0055:         * class whose identifier is <code>23</code>, then the full path that is
0056:         * generated for a property named <code>text</code> is '<code>/newsitem/23/text</code>'.
0057:         * Note that this always specifies the most recent version of the property,
0058:         * but that older versions are also available from the content store.
0059:         * <p>Before being able to use the CMF and a <code>ContentQueryManager</code>,
0060:         * you must install both of them, as in this example:
0061:         * <pre>Datasource ds = Datasources.getRepInstance().getDatasource("datasource");
0062:         *DatabaseContentFactory.getInstance(ds).install();
0063:         *new ContentQueryManager(ds, NewsItem.class).install();</pre>
0064:         * <p>Apart from the handling of content, this query manager also integrates
0065:         * the functionalities of the {@link OrdinalManager} class.
0066:         * <p>The new '{@link com.uwyn.rife.site.ConstrainedProperty#ordinal(boolean) ordinal}'
0067:         * constraint indicates which bean property will be used to order that table
0068:         * rows. When saving and deleting beans, the ordinal values will be
0069:         * automatically updated in the entire table. The
0070:         * <code>ContentQueryManager</code> also provides the {@link
0071:         * #move(Constrained, String, OrdinalManager.Direction) move}, {@link
0072:         * #up(Constrained, String) up} and {@link #down(Constrained, String) down}
0073:         * methods to easily manipulate the order of existing rows.
0074:         *
0075:         * @author Geert Bevin (gbevin[remove] at uwyn dot com)i
0076:         * @version $Revision: 3848 $
0077:         * @since 1.0
0078:         */
0079:        public class ContentQueryManager<T> extends
0080:                GenericQueryManagerDelegate<T> implements  Cloneable {
0081:            private Class mClass = null;
0082:            private Class mBackendClass = null;
0083:            private DbQueryManager mDbQueryManager = null;
0084:            private ContentManager mContentManager = null;
0085:            private String mRepository = null;
0086:
0087:            private ThreadLocal<T> mDeletedbean = new ThreadLocal<T>();
0088:
0089:            /**
0090:             * Creates a new <code>ContentQueryManager</code> instance for a specific
0091:             * class.
0092:             * <p>All content will be stored in a {@link
0093:             * com.uwyn.rife.cmf.dam.contentmanagers.DatabaseContent}.
0094:             *
0095:             * @param datasource the datasource that indicates where the data will be
0096:             * stored
0097:             * @param klass the class of the bean that will be handled by this
0098:             * <code>ContentQueryManager</code>
0099:             * @param backendClass the class the will be used by this
0100:             * <code>ContentQueryManager</code> to reference data in the backend
0101:             * @since 1.0
0102:             */
0103:            public ContentQueryManager(Datasource datasource, Class<T> klass,
0104:                    Class backendClass) {
0105:                super (datasource, klass, ClassUtils
0106:                        .shortenClassName(backendClass));
0107:
0108:                mClass = klass;
0109:                mBackendClass = backendClass;
0110:                mDbQueryManager = new DbQueryManager(datasource);
0111:                mContentManager = DatabaseContentFactory
0112:                        .getInstance(datasource);
0113:                addListener(new Listener());
0114:            }
0115:
0116:            /**
0117:             * Creates a new <code>ContentQueryManager</code> instance for a specific
0118:             * class, but with a different table name for the database storage.
0119:             * <p>All content will be stored in a {@link
0120:             * com.uwyn.rife.cmf.dam.contentmanagers.DatabaseContent}.
0121:             *
0122:             * @param datasource the datasource that indicates where the data will be
0123:             * stored
0124:             * @param klass the class of the bean that will be handled by this
0125:             * <code>ContentQueryManager</code>
0126:             * @param table the name of the database table in which the non CMF data will
0127:             * be stored
0128:             * @since 1.6
0129:             */
0130:            public ContentQueryManager(Datasource datasource, Class<T> klass,
0131:                    String table) {
0132:                super (datasource, klass, table);
0133:
0134:                mClass = klass;
0135:                mBackendClass = klass;
0136:                mDbQueryManager = new DbQueryManager(datasource);
0137:                mContentManager = DatabaseContentFactory
0138:                        .getInstance(datasource);
0139:                addListener(new Listener());
0140:            }
0141:
0142:            /**
0143:             * Creates a new <code>ContentQueryManager</code> instance for a specific
0144:             * class.
0145:             * <p>All content will be stored in a {@link
0146:             * com.uwyn.rife.cmf.dam.contentmanagers.DatabaseContent}.
0147:             *
0148:             * @param datasource the datasource that indicates where the data will be
0149:             * stored
0150:             * @param klass the class of the bean that will be handled by this
0151:             * <code>ContentQueryManager</code>
0152:             * @since 1.0
0153:             */
0154:            public ContentQueryManager(Datasource datasource, Class<T> klass) {
0155:                super (datasource, klass);
0156:
0157:                mClass = klass;
0158:                mBackendClass = klass;
0159:                mDbQueryManager = new DbQueryManager(datasource);
0160:                mContentManager = DatabaseContentFactory
0161:                        .getInstance(datasource);
0162:                addListener(new Listener());
0163:            }
0164:
0165:            /**
0166:             * Creates a new <code>ContentQueryManager</code> instance for a specific
0167:             * class.
0168:             * <p>All content will be stored in the provided
0169:             * <code>ContentManager</code> instance. This constructor is handy if you
0170:             * want to integrate a custom content manager implementation.
0171:             *
0172:             * @param datasource the datasource that indicates where the data will be
0173:             * stored
0174:             * @param klass the class of the bean that will be handled by this
0175:             * <code>ContentQueryManager</code>
0176:             * @param contentManager a <code>ContentManager</code> instance
0177:             * @since 1.0
0178:             */
0179:            public ContentQueryManager(Datasource datasource, Class<T> klass,
0180:                    ContentManager contentManager) {
0181:                super (datasource, klass);
0182:
0183:                mClass = klass;
0184:                mContentManager = contentManager;
0185:                addListener(new Listener());
0186:            }
0187:
0188:            /**
0189:             * Sets the default repository that will be used by this <code>ContentQueryManager</code>.
0190:             *
0191:             * @return this <code>ContentQueryManager</code>
0192:             * @see #getRepository
0193:             * @since 1.4
0194:             */
0195:            public ContentQueryManager<T> repository(String repository) {
0196:                mRepository = repository;
0197:
0198:                return this ;
0199:            }
0200:
0201:            /**
0202:             * Retrieves the default repository that is used by this <code>ContentQueryManager</code>.
0203:             *
0204:             * @return this <code>ContentQueryManager</code>'s repository
0205:             * @see #repository
0206:             * @since 1.4
0207:             */
0208:            public String getRepository() {
0209:                return mRepository;
0210:            }
0211:
0212:            /**
0213:             * Returns the <code>ContentManager</code> that is used to store and
0214:             * retrieve the content.
0215:             *
0216:             * @return the <code>ContentManager</code>
0217:             * @since 1.0
0218:             */
0219:            public ContentManager getContentManager() {
0220:                return mContentManager;
0221:            }
0222:
0223:            /**
0224:             * Moves the row that corresponds to the provided bean instance according
0225:             * to a property with an ordinal constraint.
0226:             *
0227:             * @param bean the bean instance that corresponds to the row that has to
0228:             * be moved
0229:             * @param propertyName the name of the property with an ordinal constraint
0230:             * @param direction {@link OrdinalManager#UP} or {@link
0231:             * OrdinalManager#DOWN}
0232:             * @return <code>true</code> if the row was moved successfully; or
0233:             * <p><code>false</code> otherwise
0234:             * @since 1.0
0235:             */
0236:            public boolean move(Constrained bean, String propertyName,
0237:                    OrdinalManager.Direction direction) {
0238:                if (null == bean)
0239:                    throw new IllegalArgumentException(
0240:                            "constrained can't be nul");
0241:                if (null == propertyName)
0242:                    throw new IllegalArgumentException(
0243:                            "propertyName can't be null");
0244:                if (0 == propertyName.length())
0245:                    throw new IllegalArgumentException(
0246:                            "propertyName can't be empty");
0247:
0248:                ConstrainedProperty property = bean
0249:                        .getConstrainedProperty(propertyName);
0250:                if (null == property) {
0251:                    throw new UnknownConstrainedPropertyException(bean
0252:                            .getClass(), propertyName);
0253:                }
0254:
0255:                if (!property.isOrdinal()) {
0256:                    throw new ExpectedOrdinalConstraintException(bean
0257:                            .getClass(), propertyName);
0258:                }
0259:
0260:                // obtain the ordinal value
0261:                int ordinal = -1;
0262:                try {
0263:                    Object ordinal_object = BeanUtils.getPropertyValue(bean,
0264:                            propertyName);
0265:                    if (!(ordinal_object instanceof  Integer)) {
0266:                        throw new InvalidOrdinalTypeException(bean.getClass(),
0267:                                propertyName);
0268:                    }
0269:                    ordinal = ((Integer) ordinal_object).intValue();
0270:                } catch (BeanUtilsException e) {
0271:                    throw new UnknownOrdinalException(bean.getClass(),
0272:                            propertyName);
0273:                }
0274:
0275:                OrdinalManager ordinals = null;
0276:
0277:                if (property.hasOrdinalRestriction()) {
0278:                    String restriction_name = property.getOrdinalRestriction();
0279:
0280:                    // initialy the ordinal manager, taking the restriction property into account
0281:                    ordinals = new OrdinalManager(getDatasource(), getTable(),
0282:                            propertyName, restriction_name);
0283:
0284:                    // obtain the restriction value
0285:                    long restriction = -1;
0286:                    try {
0287:                        Object restriction_object = BeanUtils.getPropertyValue(
0288:                                bean, restriction_name);
0289:                        if (null == restriction_object) {
0290:                            throw new OrdinalRestrictionCantBeNullException(
0291:                                    bean.getClass(),
0292:                                    property.getPropertyName(),
0293:                                    restriction_name);
0294:                        }
0295:                        if (!(restriction_object instanceof  Number)) {
0296:                            throw new InvalidOrdinalRestrictionTypeException(
0297:                                    bean.getClass(), propertyName,
0298:                                    restriction_name, restriction_object
0299:                                            .getClass());
0300:                        }
0301:                        restriction = ((Number) restriction_object).longValue();
0302:                    } catch (BeanUtilsException e) {
0303:                        throw new UnknownOrdinalRestrictionException(bean
0304:                                .getClass(), propertyName, restriction_name);
0305:                    }
0306:
0307:                    // obtain a new ordinal, taking the restriction value into account
0308:                    return ordinals.move(direction, restriction, ordinal);
0309:                } else {
0310:                    ordinals = new OrdinalManager(getDatasource(), getTable(),
0311:                            propertyName);
0312:                    return ordinals.move(direction, ordinal);
0313:                }
0314:            }
0315:
0316:            /**
0317:             * Moves the row that corresponds to the provided bean instance upwards
0318:             * according to a property with an ordinal constraint.
0319:             *
0320:             * @param bean the bean instance that corresponds to the row that has to
0321:             * be moved
0322:             * @param propertyName the name of the property with an ordinal constraint
0323:             * @return <code>true</code> if the row was moved successfully; or
0324:             * <p><code>false</code> otherwise
0325:             * @since 1.0
0326:             */
0327:            public boolean up(Constrained bean, String propertyName) {
0328:                return move(bean, propertyName, OrdinalManager.UP);
0329:            }
0330:
0331:            /**
0332:             * Moves the row that corresponds to the provided bean instance downwards
0333:             * according to a property with an ordinal constraint.
0334:             *
0335:             * @param bean the bean instance that corresponds to the row that has to
0336:             * be moved
0337:             * @param propertyName the name of the property with an ordinal constraint
0338:             * @return <code>true</code> if the row was moved successfully; or
0339:             * <p><code>false</code> otherwise
0340:             * @since 1.0
0341:             */
0342:            public boolean down(Constrained bean, String propertyName) {
0343:                return move(bean, propertyName, OrdinalManager.DOWN);
0344:            }
0345:
0346:            /**
0347:             * Empties the content of a certain bean property.
0348:             * <p>When a bean is saved, <code>null</code> content properties are
0349:             * simply ignored when the property hasn't got an <code>autoRetrieved</code>
0350:             * constraint. This is needed to make it possible to only update a
0351:             * bean's data without having to fetch the content from the back-end and
0352:             * store it together with the other data just to make a simple update.
0353:             * However, this makes it impossible to rely on <code>null</code> to
0354:             * indicate empty content. This method has thus been added explicitly for
0355:             * this purpose.
0356:             *
0357:             * @param bean the bean instance that contains the property
0358:             * @param propertyName the name of the property whose content has to be
0359:             * emptied in the database
0360:             * @return <code>true</code> if the empty content was stored successfully;
0361:             * or
0362:             * <p><code>false</code> otherwise
0363:             * @since 1.0
0364:             */
0365:            public boolean storeEmptyContent(final T bean, String propertyName) {
0366:                if (null == bean)
0367:                    throw new IllegalArgumentException(
0368:                            "constrained can't be null");
0369:                if (null == propertyName)
0370:                    throw new IllegalArgumentException(
0371:                            "propertyName can't be null");
0372:                if (0 == propertyName.length())
0373:                    throw new IllegalArgumentException(
0374:                            "propertyName can't be empty");
0375:
0376:                Constrained constrained = ConstrainedUtils
0377:                        .makeConstrainedInstance(bean);
0378:                if (null == constrained) {
0379:                    return false;
0380:                }
0381:
0382:                int id = getIdentifierValue(bean);
0383:                if (-1 == id) {
0384:                    throw new MissingIdentifierValueException(bean.getClass(),
0385:                            getIdentifierName());
0386:                }
0387:
0388:                ConstrainedProperty property = constrained
0389:                        .getConstrainedProperty(propertyName);
0390:                if (null == property) {
0391:                    throw new UnknownConstrainedPropertyException(bean
0392:                            .getClass(), propertyName);
0393:                }
0394:
0395:                if (!property.hasMimeType()) {
0396:                    throw new ExpectedMimeTypeConstraintException(bean
0397:                            .getClass(), propertyName);
0398:                }
0399:
0400:                try {
0401:                    Content content = new Content(property.getMimeType(), null)
0402:                            .fragment(property.isFragment()).name(
0403:                                    property.getName()).attributes(
0404:                                    property.getContentAttributes())
0405:                            .cachedLoadedData(property.getCachedLoadedData());
0406:
0407:                    return mContentManager.storeContent(buildCmfPath(
0408:                            constrained, id, property.getPropertyName()),
0409:                            content, property.getTransformer());
0410:                } catch (ContentManagerException e) {
0411:                    throw new DatabaseException(e);
0412:                }
0413:            }
0414:
0415:            /**
0416:             * Saves a bean.
0417:             * <p>This augments the regular <code>GenericQueryManager</code>'s
0418:             * <code>save</code> method with behaviour that correctly handles content
0419:             * or ordinal properties.
0420:             * When a bean is saved, <code>null</code> content properties are simply
0421:             * ignored when the property hasn't got an <code>autoRetrieved</code>
0422:             * constraint. This is needed to make it possible to only update a bean's
0423:             * data without having to fetch the content from the back-end and store it
0424:             * together with the other data just to make a simple update.
0425:             *
0426:             * @param bean the bean instance that has to be saved
0427:             * @return <code>true</code> if the bean was stored successfully; or
0428:             * <p><code>false</code> otherwise
0429:             * @since 1.0
0430:             */
0431:            public int save(final T bean) throws DatabaseException {
0432:                return (Integer) mDbQueryManager
0433:                        .inTransaction(new DbTransactionUser() {
0434:                            public Integer useTransaction()
0435:                                    throws InnerClassException {
0436:                                int id = -1;
0437:
0438:                                // determine if it's an update or an insert
0439:                                boolean update = false;
0440:                                id = getIdentifierValue(bean);
0441:                                if (id >= 0) {
0442:                                    update = true;
0443:                                }
0444:
0445:                                // handle the pre-storage constraints logic
0446:                                Constrained constrained = ConstrainedUtils
0447:                                        .makeConstrainedInstance(bean);
0448:                                Collection<ConstrainedProperty> properties = null;
0449:                                if (constrained != null) {
0450:                                    properties = constrained
0451:                                            .getConstrainedProperties();
0452:
0453:                                    for (ConstrainedProperty property : properties) {
0454:                                        if (!update) {
0455:                                            if (property.isOrdinal()) {
0456:                                                try {
0457:                                                    OrdinalManager ordinals = null;
0458:
0459:                                                    int new_ordinal = -1;
0460:
0461:                                                    if (property
0462:                                                            .hasOrdinalRestriction()) {
0463:                                                        String restriction_name = property
0464:                                                                .getOrdinalRestriction();
0465:
0466:                                                        // initialize the ordinal manager, taking the restriction property into account
0467:                                                        ordinals = new OrdinalManager(
0468:                                                                getDatasource(),
0469:                                                                getTable(),
0470:                                                                property
0471:                                                                        .getPropertyName(),
0472:                                                                restriction_name);
0473:
0474:                                                        // obtain the restriction value
0475:                                                        long restriction = -1;
0476:                                                        try {
0477:                                                            Object restriction_object = BeanUtils
0478:                                                                    .getPropertyValue(
0479:                                                                            bean,
0480:                                                                            restriction_name);
0481:                                                            if (null == restriction_object) {
0482:                                                                throw new OrdinalRestrictionCantBeNullException(
0483:                                                                        bean
0484:                                                                                .getClass(),
0485:                                                                        property
0486:                                                                                .getPropertyName(),
0487:                                                                        restriction_name);
0488:                                                            }
0489:                                                            if (!(restriction_object instanceof  Number)) {
0490:                                                                throw new InvalidOrdinalRestrictionTypeException(
0491:                                                                        bean
0492:                                                                                .getClass(),
0493:                                                                        property
0494:                                                                                .getPropertyName(),
0495:                                                                        restriction_name,
0496:                                                                        restriction_object
0497:                                                                                .getClass());
0498:                                                            }
0499:                                                            restriction = ((Number) restriction_object)
0500:                                                                    .longValue();
0501:                                                        } catch (BeanUtilsException e) {
0502:                                                            throw new UnknownOrdinalRestrictionException(
0503:                                                                    bean
0504:                                                                            .getClass(),
0505:                                                                    property
0506:                                                                            .getPropertyName(),
0507:                                                                    restriction_name);
0508:                                                        }
0509:
0510:                                                        // obtain a new ordinal, taking the restriction value into account
0511:                                                        new_ordinal = ordinals
0512:                                                                .obtainInsertOrdinal(restriction);
0513:                                                    } else {
0514:                                                        ordinals = new OrdinalManager(
0515:                                                                getDatasource(),
0516:                                                                getTable(),
0517:                                                                property
0518:                                                                        .getPropertyName());
0519:                                                        new_ordinal = ordinals
0520:                                                                .obtainInsertOrdinal();
0521:                                                    }
0522:                                                    BeanUtils
0523:                                                            .setPropertyValue(
0524:                                                                    bean,
0525:                                                                    property
0526:                                                                            .getPropertyName(),
0527:                                                                    new_ordinal);
0528:                                                } catch (BeanUtilsException e) {
0529:                                                    throw new DatabaseException(
0530:                                                            e);
0531:                                                }
0532:                                            }
0533:                                        }
0534:                                    }
0535:                                }
0536:
0537:                                // store the new bean or update it
0538:                                id = ContentQueryManager.super .save(bean);
0539:
0540:                                return id;
0541:                            }
0542:                        });
0543:            }
0544:
0545:            /**
0546:             * Restores a bean according to its ID.
0547:             * <p>This augments the regular <code>GenericQueryManager</code>'s
0548:             * <code>restore</code> method with behaviour that correctly handles
0549:             * content properties.
0550:             *
0551:             * @param objectId the ID of the bean that has to be restored
0552:             * @return the bean instance if it was restored successfully; or
0553:             * <p><code>null</code> if it couldn't be found
0554:             * @since 1.0
0555:             */
0556:            public T restore(int objectId) throws DatabaseException {
0557:                return super .restore(objectId);
0558:            }
0559:
0560:            /**
0561:             * Restores the first bean from a <code>RestoreQuery</code>.
0562:             * <p>This augments the regular <code>GenericQueryManager</code>'s
0563:             * <code>restore</code> method with behaviour that correctly handles
0564:             * content properties.
0565:             *
0566:             * @param query the query that will be used to restore the beans
0567:             * @return the first bean instance that was found; or
0568:             * <p><code>null</code> if no beans could be found
0569:             * @since 1.0
0570:             */
0571:            public T restoreFirst(RestoreQuery query) throws DatabaseException {
0572:                return super .restoreFirst(query);
0573:            }
0574:
0575:            /**
0576:             * Restores all beans.
0577:             * <p>This augments the regular <code>GenericQueryManager</code>'s
0578:             * <code>restore</code> method with behaviour that correctly handles
0579:             * content properties.
0580:             *
0581:             * @return the list of beans; or
0582:             * <p><code>null</code> if no beans could be found
0583:             * @since 1.0
0584:             */
0585:            public List<T> restore() throws DatabaseException {
0586:                return super .restore();
0587:            }
0588:
0589:            /**
0590:             * Restores all beans from a <code>RestoreQuery</code>.
0591:             * <p>This augments the regular <code>GenericQueryManager</code>'s
0592:             * <code>restore</code> method with behaviour that correctly handles
0593:             * content properties.
0594:             *
0595:             * @param query the query that will be used to restore the beans
0596:             * @return the list of beans; or
0597:             * <p><code>null</code> if no beans could be found
0598:             * @since 1.0
0599:             */
0600:            public List<T> restore(RestoreQuery query) throws DatabaseException {
0601:                return super .restore(query);
0602:            }
0603:
0604:            private void restoreContent(int objectId, final T bean) {
0605:                Constrained constrained = ConstrainedUtils
0606:                        .makeConstrainedInstance(bean);
0607:                if (constrained != null) {
0608:                    Collection<ConstrainedProperty> properties = constrained
0609:                            .getConstrainedProperties();
0610:                    for (ConstrainedProperty property : properties) {
0611:                        if (property.hasMimeType()
0612:                                && property.isAutoRetrieved()) {
0613:                            mContentManager
0614:                                    .useContentData(
0615:                                            buildCmfPath(constrained, objectId,
0616:                                                    property.getPropertyName()),
0617:                                            new ContentDataUser<Object, ConstrainedProperty>(
0618:                                                    property) {
0619:                                                public Object useContentData(
0620:                                                        Object contentData)
0621:                                                        throws InnerClassException {
0622:                                                    try {
0623:                                                        BeanUtils
0624:                                                                .setPropertyValue(
0625:                                                                        bean,
0626:                                                                        getData()
0627:                                                                                .getPropertyName(),
0628:                                                                        contentData);
0629:                                                    } catch (BeanUtilsException e) {
0630:                                                        throw new DatabaseException(
0631:                                                                e);
0632:                                                    } catch (ContentManagerException e) {
0633:                                                        throw new DatabaseException(
0634:                                                                e);
0635:                                                    }
0636:                                                    return null;
0637:                                                }
0638:                                            });
0639:                        }
0640:                    }
0641:                }
0642:            }
0643:
0644:            /**
0645:             * Deletes a bean according to its ID.
0646:             * <p>This augments the regular <code>GenericQueryManager</code>'s
0647:             * <code>restore</code> method with behaviour that correctly handles
0648:             * content and ordinal properties.
0649:             *
0650:             * @param objectId the ID of the bean that has to be restored
0651:             * @return <code>true</code> if the bean was deleted successfully; or
0652:             * <p><code>false</code> if it couldn't be found
0653:             * @since 1.0
0654:             */
0655:            public boolean delete(final int objectId) throws DatabaseException {
0656:                Boolean result = mDbQueryManager
0657:                        .inTransaction(new DbTransactionUser() {
0658:                            public Boolean useTransaction()
0659:                                    throws InnerClassException {
0660:                                T bean = restore(objectId);
0661:                                if (null == bean) {
0662:                                    return false;
0663:                                }
0664:
0665:                                mDeletedbean.set(bean);
0666:                                try {
0667:                                    if (ContentQueryManager.super 
0668:                                            .delete(objectId)) {
0669:                                        return true;
0670:                                    }
0671:                                } finally {
0672:                                    mDeletedbean.set(null);
0673:                                }
0674:
0675:                                return false;
0676:                            }
0677:                        });
0678:
0679:                return null != result && result.booleanValue();
0680:            }
0681:
0682:            /**
0683:             * Checks if there's content available for a certain property of a bean.
0684:             *
0685:             * @param bean the bean instance that will be checked
0686:             * @param propertyName the name of the property whose content availability
0687:             * will be checked
0688:             * @return <code>true</code> if content is available; or
0689:             * <p><code>false</code> otherwise
0690:             * @since 1.0
0691:             */
0692:            public boolean hasContent(T bean, String propertyName)
0693:                    throws DatabaseException {
0694:                Constrained constrained = ConstrainedUtils
0695:                        .makeConstrainedInstance(bean);
0696:
0697:                return hasContent(constrained, getIdentifierValue(bean),
0698:                        propertyName);
0699:            }
0700:
0701:            /**
0702:             * Checks if there's content available for a certain property of a bean.
0703:             *
0704:             * @param objectId the ID of the bean instance that will be checked
0705:             * @param propertyName the name of the property whose content availability
0706:             * will be checked
0707:             * @return <code>true</code> if content is available; or
0708:             * <p><code>false</code> otherwise
0709:             * @since 1.0
0710:             */
0711:            public boolean hasContent(int objectId, String propertyName)
0712:                    throws DatabaseException {
0713:                Constrained constrained = ConstrainedUtils
0714:                        .getConstrainedInstance(mClass);
0715:
0716:                return hasContent(constrained, objectId, propertyName);
0717:            }
0718:
0719:            private boolean hasContent(Constrained constrained, int objectId,
0720:                    String propertyName) throws DatabaseException {
0721:                try {
0722:                    return mContentManager.hasContentData(buildCmfPath(
0723:                            constrained, objectId, propertyName));
0724:                } catch (ContentManagerException e) {
0725:                    throw new DatabaseException(e);
0726:                }
0727:            }
0728:
0729:            /**
0730:             * Builds the path that is used by the <code>ContentQueryManager</code>
0731:             * for a certain bean and property.
0732:             *
0733:             * @param bean the bean instance that will be used to construct the path
0734:             * @param propertyName the name of the property that will be used to
0735:             * construct the path
0736:             * @return the requested path
0737:             * @since 1.0
0738:             */
0739:            public String buildCmfPath(T bean, String propertyName) {
0740:                Constrained constrained = ConstrainedUtils
0741:                        .makeConstrainedInstance(bean);
0742:
0743:                return buildCmfPath(constrained, getIdentifierValue(bean),
0744:                        propertyName, true);
0745:            }
0746:
0747:            /**
0748:             * Builds the path that is used by the <code>ContentQueryManager</code>
0749:             * for a certain bean ID and property.
0750:             *
0751:             * @param objectId the bean ID that will be used to construct the path
0752:             * @param propertyName the name of the property that will be used to
0753:             * construct the path
0754:             * @return the requested path
0755:             * @since 1.0
0756:             */
0757:            public String buildCmfPath(int objectId, String propertyName) {
0758:                Constrained constrained = ConstrainedUtils
0759:                        .getConstrainedInstance(mClass);
0760:
0761:                return buildCmfPath(constrained, objectId, propertyName, true);
0762:            }
0763:
0764:            /**
0765:             * Builds the path that is used by the <code>ServeContent</code> element
0766:             * for a certain bean and property.
0767:             * <p>Any declaration of the repository name will be ignore, since the
0768:             * <code>ServeContent</code> element doesn't allow you to provide this
0769:             * through the URL for safety reasons.
0770:             *
0771:             * @param bean the bean instance that will be used to construct the path
0772:             * @param propertyName the name of the property that will be used to
0773:             * construct the path
0774:             * @return the requested path
0775:             * @since 1.4
0776:             */
0777:            public String buildServeContentPath(T bean, String propertyName) {
0778:                Constrained constrained = ConstrainedUtils
0779:                        .makeConstrainedInstance(bean);
0780:
0781:                return buildCmfPath(constrained, getIdentifierValue(bean),
0782:                        propertyName, false);
0783:            }
0784:
0785:            /**
0786:             * Builds the path that is used by the <code>ServeContent</code> element
0787:             * for a certain bean ID and property.
0788:             * <p>Any declaration of the repository name will be ignore, since the
0789:             * <code>ServeContent</code> element doesn't allow you to provide this
0790:             * through the URL for safety reasons.
0791:             *
0792:             * @param objectId the bean ID that will be used to construct the path
0793:             * @param propertyName the name of the property that will be used to
0794:             * construct the path
0795:             * @return the requested path
0796:             * @since 1.4
0797:             */
0798:            public String buildServeContentPath(int objectId,
0799:                    String propertyName) {
0800:                Constrained constrained = ConstrainedUtils
0801:                        .getConstrainedInstance(mClass);
0802:
0803:                return buildCmfPath(constrained, objectId, propertyName, false);
0804:            }
0805:
0806:            private String buildCmfPath(Constrained constrained, int objectId,
0807:                    String propertyName) {
0808:                return buildCmfPath(constrained, objectId, propertyName, true);
0809:            }
0810:
0811:            private String buildCmfPath(Constrained constrained, int objectId,
0812:                    String propertyName, boolean useRepository) {
0813:                String repository = null;
0814:                if (useRepository) {
0815:                    if (mRepository != null) {
0816:                        repository = mRepository;
0817:                    }
0818:                    if (constrained != null) {
0819:                        ConstrainedProperty property = constrained
0820:                                .getConstrainedProperty(propertyName);
0821:                        if (property != null && property.hasRepository()) {
0822:                            repository = property.getRepository();
0823:                        }
0824:                    }
0825:                }
0826:
0827:                StringBuilder path = new StringBuilder("");
0828:                if (repository != null && repository.length() > 0) {
0829:                    path.append(repository);
0830:                    path.append(":");
0831:                }
0832:                path.append("/");
0833:                String classname = mBackendClass.getName();
0834:                classname = classname.substring(classname.lastIndexOf(".") + 1);
0835:                path.append(StringUtils.encodeUrl(classname));
0836:                path.append("/");
0837:                path.append(objectId);
0838:                path.append("/");
0839:                path.append(StringUtils.encodeUrl(propertyName));
0840:
0841:                return path.toString().toLowerCase();
0842:            }
0843:
0844:            /**
0845:             * Retrieves a content data representation for use in html.
0846:             * <p>This is mainly used to integrate content data inside a html
0847:             * document. For instance, html content will be displayed as-is, while
0848:             * image content will cause an image tag to be generated with the correct
0849:             * source URL to serve the image.
0850:             *
0851:             * @param bean the bean instance that contains the data
0852:             * @param propertyName the name of the property whose html representation
0853:             * will be provided
0854:             * @param element an active element instance
0855:             * @param serveContentExitName the exit name that leads to a {@link
0856:             * com.uwyn.rife.cmf.elements.ServeContent ServeContent} element. This will
0857:             * be used to generate URLs for content that can't be directly displayed
0858:             * in-line.
0859:             * @return the html content representation
0860:             * @exception ContentManagerException if an unexpected error occurred
0861:             * @since 1.0
0862:             */
0863:            public String getContentForHtml(T bean, String propertyName,
0864:                    Element element, String serveContentExitName)
0865:                    throws ContentManagerException {
0866:                return getContentManager().getContentForHtml(
0867:                        buildCmfPath(bean, propertyName), element,
0868:                        serveContentExitName);
0869:            }
0870:
0871:            /**
0872:             * Retrieves a content data representation for use in html.
0873:             * <p>This is mainly used to integrate content data inside a html
0874:             * document. For instance, html content will be displayed as-is, while
0875:             * image content will cause an image tag to be generated with the correct
0876:             * source URL to serve the image.
0877:             *
0878:             * @param objectId the ID of the bean that contains the data
0879:             * @param propertyName the name of the property whose html representation
0880:             * will be provided
0881:             * @param element an active element instance
0882:             * @param serveContentExitName the exit name that leads to a {@link
0883:             * com.uwyn.rife.cmf.elements.ServeContent ServeContent} element. This will
0884:             * be used to generate URLs for content that can't be directly displayed
0885:             * in-line.
0886:             * @return the html content representation
0887:             * @exception ContentManagerException if an unexpected error occurred
0888:             * @since 1.0
0889:             */
0890:            public String getContentForHtml(int objectId, String propertyName,
0891:                    Element element, String serveContentExitName)
0892:                    throws ContentManagerException {
0893:                return getContentManager().getContentForHtml(
0894:                        buildCmfPath(objectId, propertyName), element,
0895:                        serveContentExitName);
0896:            }
0897:
0898:            /**
0899:             * Simply clones the instance with the default clone method. This creates
0900:             * a shallow copy of all fields and the clone will in fact just be another
0901:             * reference to the same underlying data. The independence of each cloned
0902:             * instance is consciously not respected since they rely on resources that
0903:             * can't be cloned.
0904:             *
0905:             * @since 1.0
0906:             */
0907:            public Object clone() {
0908:                try {
0909:                    return super .clone();
0910:                } catch (CloneNotSupportedException e) {
0911:                    ///CLOVER:OFF
0912:                    // this should never happen
0913:                    Logger.getLogger("com.uwyn.rife.cmf").severe(
0914:                            ExceptionUtils.getExceptionStackTrace(e));
0915:                    return null;
0916:                    ///CLOVER:ON
0917:                }
0918:            }
0919:
0920:            class Listener implements  GenericQueryManagerListener<T> {
0921:                public void installed() {
0922:                }
0923:
0924:                public void removed() {
0925:                }
0926:
0927:                public void inserted(T bean) {
0928:                    saved(bean);
0929:                }
0930:
0931:                public void updated(T bean) {
0932:                    saved(bean);
0933:                }
0934:
0935:                public void saved(T bean) {
0936:                    Constrained constrained = ConstrainedUtils
0937:                            .makeConstrainedInstance(bean);
0938:                    Collection<ConstrainedProperty> properties = null;
0939:                    if (constrained != null) {
0940:                        properties = constrained.getConstrainedProperties();
0941:                    }
0942:
0943:                    // process the properties that have to be handled after the saving of the bean
0944:                    if (properties != null) {
0945:                        int id = getIdentifierValue(bean);
0946:
0947:                        for (ConstrainedProperty property : properties) {
0948:                            if (property.hasMimeType()) {
0949:                                try {
0950:                                    Object value = BeanUtils.getPropertyValue(
0951:                                            bean, property.getPropertyName());
0952:                                    if (value != null
0953:                                            || property.isAutoRetrieved()) {
0954:                                        Content content = new Content(property
0955:                                                .getMimeType(), value)
0956:                                                .fragment(property.isFragment())
0957:                                                .name(property.getName())
0958:                                                .attributes(
0959:                                                        property
0960:                                                                .getContentAttributes())
0961:                                                .cachedLoadedData(
0962:                                                        property
0963:                                                                .getCachedLoadedData());
0964:
0965:                                        mContentManager
0966:                                                .storeContent(
0967:                                                        buildCmfPath(
0968:                                                                constrained,
0969:                                                                id,
0970:                                                                property
0971:                                                                        .getPropertyName()),
0972:                                                        content,
0973:                                                        property
0974:                                                                .getTransformer());
0975:                                    }
0976:                                } catch (BeanUtilsException e) {
0977:                                    throw new DatabaseException(e);
0978:                                } catch (ContentManagerException e) {
0979:                                    throw new DatabaseException(e);
0980:                                }
0981:                            }
0982:                        }
0983:                    }
0984:                }
0985:
0986:                public void restored(T bean) {
0987:                    restoreContent(getIdentifierValue(bean), bean);
0988:                }
0989:
0990:                public void deleted(int objectId) {
0991:                    T bean = mDeletedbean.get();
0992:                    if (null == bean) {
0993:                        return;
0994:                    }
0995:
0996:                    Constrained constrained = ConstrainedUtils
0997:                            .makeConstrainedInstance(bean);
0998:                    if (constrained != null) {
0999:                        Collection<ConstrainedProperty> properties = constrained
1000:                                .getConstrainedProperties();
1001:                        for (ConstrainedProperty property : properties) {
1002:                            if (property.hasMimeType()) {
1003:                                mContentManager.deleteContent(buildCmfPath(
1004:                                        constrained, objectId, property
1005:                                                .getPropertyName()));
1006:                            } else if (property.isOrdinal()) {
1007:                                OrdinalManager ordinals = null;
1008:                                if (property.hasOrdinalRestriction()) {
1009:                                    String restriction_name = property
1010:                                            .getOrdinalRestriction();
1011:
1012:                                    // initialize the ordinal manager, taking the restriction property into account
1013:                                    ordinals = new OrdinalManager(
1014:                                            getDatasource(), getTable(),
1015:                                            property.getPropertyName(),
1016:                                            restriction_name);
1017:
1018:                                    // obtain the restriction value
1019:                                    long restriction = -1;
1020:                                    try {
1021:                                        Object restriction_object = BeanUtils
1022:                                                .getPropertyValue(bean,
1023:                                                        restriction_name);
1024:                                        if (null == restriction_object) {
1025:                                            throw new OrdinalRestrictionCantBeNullException(
1026:                                                    bean.getClass(), property
1027:                                                            .getPropertyName(),
1028:                                                    restriction_name);
1029:                                        }
1030:                                        if (!(restriction_object instanceof  Number)) {
1031:                                            throw new InvalidOrdinalRestrictionTypeException(
1032:                                                    bean.getClass(), property
1033:                                                            .getPropertyName(),
1034:                                                    restriction_name,
1035:                                                    restriction_object
1036:                                                            .getClass());
1037:                                        }
1038:                                        restriction = ((Number) restriction_object)
1039:                                                .longValue();
1040:                                    } catch (BeanUtilsException e) {
1041:                                        throw new UnknownOrdinalRestrictionException(
1042:                                                bean.getClass(), property
1043:                                                        .getPropertyName(),
1044:                                                restriction_name);
1045:                                    }
1046:
1047:                                    // tighten the remaining ordinals, taking the restriction value into account
1048:                                    ordinals.tighten(restriction);
1049:                                } else {
1050:                                    ordinals = new OrdinalManager(
1051:                                            getDatasource(), getTable(),
1052:                                            property.getPropertyName());
1053:                                    ordinals.tighten();
1054:                                }
1055:                            }
1056:                        }
1057:                    }
1058:                }
1059:            }
1060:
1061:            public <OtherBeanType> GenericQueryManager<OtherBeanType> createNewManager(
1062:                    Class<OtherBeanType> type) {
1063:                return new ContentQueryManager(getDatasource(), type,
1064:                        mContentManager);
1065:            }
1066:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.