Source Code Cross Referenced for AssignmentEngineBean.java in  » J2EE » fleXive » com » flexive » ejb » beans » structure » 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 » J2EE » fleXive » com.flexive.ejb.beans.structure 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /***************************************************************
0002:         *  This file is part of the [fleXive](R) project.
0003:         *
0004:         *  Copyright (c) 1999-2008
0005:         *  UCS - unique computing solutions gmbh (http://www.ucs.at)
0006:         *  All rights reserved
0007:         *
0008:         *  The [fleXive](R) project is free software; you can redistribute
0009:         *  it and/or modify it under the terms of the GNU General Public
0010:         *  License as published by the Free Software Foundation;
0011:         *  either version 2 of the License, or (at your option) any
0012:         *  later version.
0013:         *
0014:         *  The GNU General Public License can be found at
0015:         *  http://www.gnu.org/copyleft/gpl.html.
0016:         *  A copy is found in the textfile GPL.txt and important notices to the
0017:         *  license from the author are found in LICENSE.txt distributed with
0018:         *  these libraries.
0019:         *
0020:         *  This library is distributed in the hope that it will be useful,
0021:         *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0022:         *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0023:         *  GNU General Public License for more details.
0024:         *
0025:         *  For further information about UCS - unique computing solutions gmbh,
0026:         *  please see the company website: http://www.ucs.at
0027:         *
0028:         *  For further information about [fleXive](R), please see the
0029:         *  project website: http://www.flexive.org
0030:         *
0031:         *
0032:         *  This copyright notice MUST APPEAR in all copies of the file!
0033:         ***************************************************************/package com.flexive.ejb.beans.structure;
0034:
0035:        import com.flexive.core.Database;
0036:        import static com.flexive.core.DatabaseConst.*;
0037:        import com.flexive.core.storage.ContentStorage;
0038:        import com.flexive.core.storage.StorageManager;
0039:        import com.flexive.core.structure.StructureLoader;
0040:        import com.flexive.shared.CacheAdmin;
0041:        import com.flexive.shared.FxContext;
0042:        import com.flexive.shared.FxLanguage;
0043:        import com.flexive.shared.XPathElement;
0044:        import com.flexive.shared.cache.FxCacheException;
0045:        import com.flexive.shared.content.FxPermissionUtils;
0046:        import com.flexive.shared.exceptions.*;
0047:        import com.flexive.shared.interfaces.*;
0048:        import com.flexive.shared.security.Role;
0049:        import com.flexive.shared.security.UserTicket;
0050:        import com.flexive.shared.structure.*;
0051:        import com.flexive.shared.value.FxString;
0052:        import org.apache.commons.logging.Log;
0053:        import org.apache.commons.logging.LogFactory;
0054:
0055:        import javax.annotation.Resource;
0056:        import javax.ejb.*;
0057:        import java.sql.*;
0058:        import java.util.ArrayList;
0059:        import java.util.List;
0060:
0061:        /**
0062:         * Structure Assignment management
0063:         * <p/>
0064:         * TODO's:
0065:         * -property/group removal
0066:         * -check if modification/creation even possible in case instances exist
0067:         * -implement all known changeable flags
0068:         *
0069:         * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
0070:         */
0071:        @Stateless(name="AssignmentEngine")
0072:        @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0073:        @TransactionManagement(TransactionManagementType.CONTAINER)
0074:        public class AssignmentEngineBean implements  AssignmentEngine,
0075:                AssignmentEngineLocal {
0076:
0077:            private static transient Log LOG = LogFactory
0078:                    .getLog(AssignmentEngineBean.class);
0079:
0080:            @Resource
0081:            javax.ejb.SessionContext ctx;
0082:
0083:            @EJB
0084:            SequencerEngineLocal seq;
0085:
0086:            @EJB
0087:            HistoryTrackerEngineLocal htracker;
0088:
0089:            /**
0090:             * {@inheritDoc}
0091:             */
0092:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
0093:            public long createProperty(FxPropertyEdit property,
0094:                    String parentXPath) throws FxApplicationException {
0095:                return createProperty(FxType.ROOT_ID, property, parentXPath);
0096:            }
0097:
0098:            /**
0099:             * {@inheritDoc}
0100:             */
0101:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
0102:            public long createProperty(long typeId, FxPropertyEdit property,
0103:                    String parentXPath) throws FxApplicationException {
0104:                return createProperty(typeId, property, parentXPath, property
0105:                        .getName());
0106:            }
0107:
0108:            /**
0109:             * {@inheritDoc}
0110:             */
0111:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
0112:            public long createProperty(long typeId, FxPropertyEdit property,
0113:                    String parentXPath, String assignmentAlias)
0114:                    throws FxApplicationException {
0115:                FxPermissionUtils.checkRole(FxContext.get().getTicket(),
0116:                        Role.StructureManagement);
0117:                Connection con = null;
0118:                PreparedStatement ps = null;
0119:                StringBuilder sql = new StringBuilder(2000);
0120:                long newPropertyId;
0121:                long newAssignmentId;
0122:                try {
0123:                    parentXPath = parentXPath.toUpperCase();
0124:                    assignmentAlias = assignmentAlias.toUpperCase();
0125:                    FxType type = CacheAdmin.getEnvironment().getType(typeId);
0126:                    FxAssignment tmp = type.getAssignment(parentXPath);
0127:                    if (tmp != null && tmp instanceof  FxPropertyAssignment)
0128:                        throw new FxInvalidParameterException(
0129:                                "ex.structure.assignment.noGroup", parentXPath);
0130:                    property.checkConsistency();
0131:                    //parentXPath is valid, create the property, then assign it to root
0132:                    newPropertyId = seq.getId(SequencerEngine.System.TYPEPROP);
0133:                    con = Database.getDbConnection();
0134:                    //create property, no checks for existing names are performed as this is handled with unique keys
0135:                    sql.append("INSERT INTO ").append(TBL_STRUCT_PROPERTIES).
0136:                    //               1  2    3          4          5               6        7
0137:                            append(
0138:                                    "(ID,NAME,DEFMINMULT,DEFMAXMULT,MAYOVERRIDEMULT,DATATYPE,REFTYPE,"
0139:                                            +
0140:                                            //8                9   10             11      12
0141:                                            "ISFULLTEXTINDEXED,ACL,MAYOVERRIDEACL,REFLIST,UNIQUEMODE,"
0142:                                            + "SYSINTERNAL)VALUES("
0143:                                            + "?,?,?,?,?,"
0144:                                            + "?,?,?,?,?,?,?,FALSE)");
0145:                    ps = con.prepareStatement(sql.toString());
0146:                    ps.setLong(1, newPropertyId);
0147:                    ps.setString(2, property.getName());
0148:                    ps.setInt(3, property.getMultiplicity().getMin());
0149:                    ps.setInt(4, property.getMultiplicity().getMax());
0150:                    ps.setBoolean(5, property.mayOverrideBaseMultiplicity());
0151:                    ps.setLong(6, property.getDataType().getId());
0152:                    if (property.hasReferencedType())
0153:                        ps.setLong(7, property.getReferencedType().getId());
0154:                    else
0155:                        ps.setNull(7, java.sql.Types.NUMERIC);
0156:                    ps.setBoolean(8, property.isFulltextIndexed());
0157:                    ps.setLong(9, property.getACL().getId());
0158:                    ps.setBoolean(10, property.mayOverrideACL());
0159:                    if (property.hasReferencedList())
0160:                        ps.setLong(11, property.getReferencedList().getId());
0161:                    else
0162:                        ps.setNull(11, java.sql.Types.NUMERIC);
0163:                    ps.setInt(12, property.getUniqueMode().getId());
0164:                    if (!property.isAutoUniquePropertyName())
0165:                        ps.executeUpdate();
0166:                    else {
0167:                        int counter = 0;
0168:                        boolean isok = false;
0169:                        while (!isok && counter < 200) { //200 tries max
0170:                            try {
0171:                                if (counter > 0) {
0172:                                    ps.setString(2, property.getName() + "_"
0173:                                            + counter);
0174:                                }
0175:                                ps.executeUpdate();
0176:                                isok = true;
0177:                            } catch (SQLException e) {
0178:                                if (!Database.isUniqueConstraintViolation(e)
0179:                                        || counter >= 200)
0180:                                    throw e;
0181:                            }
0182:                            counter++;
0183:                        }
0184:                    }
0185:                    Database.storeFxString(new FxString[] {
0186:                            property.getLabel(), property.getHint(),
0187:                            property.getDefaultValue() }, con,
0188:                            TBL_STRUCT_PROPERTIES, new String[] {
0189:                                    "DESCRIPTION", "HINT", "DEFAULT_VALUE" },
0190:                            "ID", newPropertyId);
0191:                    ps.close();
0192:                    sql.setLength(0);
0193:                    //calc new position
0194:                    sql.append("SELECT COALESCE(MAX(POS)+1,0) FROM ").append(
0195:                            TBL_STRUCT_ASSIGNMENTS).append(
0196:                            " WHERE PARENTGROUP=? AND TYPEDEF=?");
0197:                    ps = con.prepareStatement(sql.toString());
0198:                    ps.setLong(1, (tmp == null ? FxAssignment.NO_PARENT : tmp
0199:                            .getId()));
0200:                    ps.setLong(2, typeId);
0201:                    ResultSet rs = ps.executeQuery();
0202:                    long pos = 0;
0203:                    if (rs != null && rs.next()) {
0204:                        if (rs.wasNull())
0205:                            pos = 0; //actually impossible to happen
0206:                        else
0207:                            pos = rs.getLong(1);
0208:                    }
0209:                    ps.close();
0210:                    storeOptions(con, TBL_PROPERTY_OPTIONS, "ID",
0211:                            newPropertyId, null, property.getOptions());
0212:                    sql.setLength(0);
0213:                    //create root assignment
0214:                    sql.append("INSERT INTO ")
0215:                            .append(TBL_STRUCT_ASSIGNMENTS)
0216:                            .
0217:                            //               1  2     3       4       5       6       7       8   9     10    11    12          13
0218:                            append(
0219:                                    "(ID,ATYPE,ENABLED,TYPEDEF,MINMULT,MAXMULT,DEFMULT,POS,XPATH,XALIAS,BASE,PARENTGROUP,APROPERTY,"
0220:                                            +
0221:                                            //14
0222:                                            "ACL)"
0223:                                            + "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
0224:                    ps = con.prepareStatement(sql.toString());
0225:                    newAssignmentId = seq
0226:                            .getId(SequencerEngine.System.ASSIGNMENT);
0227:                    ps.setLong(1, newAssignmentId);
0228:                    ps.setInt(2, FxAssignment.TYPE_PROPERTY);
0229:                    ps.setBoolean(3, true);
0230:                    ps.setLong(4, typeId);
0231:                    ps.setInt(5, property.getMultiplicity().getMin());
0232:                    ps.setInt(6, property.getMultiplicity().getMax());
0233:                    if (property.getMultiplicity().isValid(
0234:                            property.getAssignmentDefaultMultiplicity())) {
0235:                        ps.setInt(7, property
0236:                                .getAssignmentDefaultMultiplicity());
0237:                    } else {
0238:                        //default is min(min,1).
0239:                        ps
0240:                                .setInt(
0241:                                        7,
0242:                                        property.getMultiplicity().getMin() > 1 ? property
0243:                                                .getMultiplicity().getMin()
0244:                                                : 1);
0245:                    }
0246:                    ps.setLong(8, pos);
0247:                    if (parentXPath == null || "/".equals(parentXPath))
0248:                        parentXPath = "";
0249:                    ps.setString(9, type.getName() + parentXPath + "/"
0250:                            + assignmentAlias);
0251:                    ps.setString(10, assignmentAlias);
0252:                    ps.setNull(11, Types.NUMERIC);
0253:                    if (tmp == null)
0254:                        ps.setLong(12, FxAssignment.NO_PARENT);
0255:                    else
0256:                        ps.setLong(12, tmp.getId());
0257:                    ps.setLong(13, newPropertyId);
0258:                    ps.setLong(14, property.getACL().getId());
0259:                    ps.executeUpdate();
0260:                    Database.storeFxString(new FxString[] {
0261:                            property.getLabel(), property.getHint(),
0262:                            property.getDefaultValue() }, con,
0263:                            TBL_STRUCT_ASSIGNMENTS, new String[] {
0264:                                    "DESCRIPTION", "HINT", "DEFAULT_VALUE" },
0265:                            "ID", newAssignmentId);
0266:                    StructureLoader.reload(con);
0267:                    htracker.track(type, "history.assignment.createProperty",
0268:                            property.getName(), type.getId(), type.getName());
0269:                    createInheritedAssignments(CacheAdmin.getEnvironment()
0270:                            .getAssignment(newAssignmentId), con, ps, sql, type
0271:                            .getDerivedTypes());
0272:                } catch (FxNotFoundException e) {
0273:                    ctx.setRollbackOnly();
0274:                    throw new FxCreateException(e);
0275:                } catch (FxLoadException e) {
0276:                    ctx.setRollbackOnly();
0277:                    throw new FxCreateException(e);
0278:                } catch (SQLException e) {
0279:                    final boolean uniqueConstraintViolation = Database
0280:                            .isUniqueConstraintViolation(e);
0281:                    ctx.setRollbackOnly();
0282:                    if (uniqueConstraintViolation)
0283:                        throw new FxEntryExistsException(
0284:                                "ex.structure.property.exists", property
0285:                                        .getName(),
0286:                                (parentXPath.length() == 0 ? "/" : parentXPath));
0287:                    throw new FxCreateException(LOG, e, "ex.db.sqlError", e
0288:                            .getMessage());
0289:                } catch (FxCacheException e) {
0290:                    ctx.setRollbackOnly();
0291:                    throw new FxCreateException(e, "ex.cache", e.getMessage());
0292:                } finally {
0293:                    Database.closeObjects(AssignmentEngineBean.class, con, ps);
0294:                }
0295:                return newAssignmentId;
0296:            }
0297:
0298:            /*
0299:             * Updates the options of an FxGroup
0300:             * Before the options are updated, they are compared against the options that are
0301:             * already stored in the DB. If there are changes, all present options are deleted
0302:             * in the DB and newly created afterwards from the assignment's option list.
0303:             *
0304:             * @return if the options changed.
0305:             */
0306:
0307:            private boolean updateGroupOptions(Connection con, FxGroupEdit group)
0308:                    throws SQLException {
0309:                boolean changed = false;
0310:                FxGroupEdit org = new FxGroupEdit(CacheAdmin.getEnvironment()
0311:                        .getGroup(group.getId()));
0312:                if (org.getOptions().size() != group.getOptions().size()) {
0313:                    changed = true;
0314:                } else {
0315:                    for (int i = 0; i < org.getOptions().size(); i++) {
0316:                        FxStructureOption orgOpt = org.getOptions().get(i);
0317:                        FxStructureOption propOpt = group.getOption(orgOpt
0318:                                .getKey());
0319:                        if (!orgOpt.equals(propOpt)) {
0320:                            changed = true;
0321:                            break;
0322:                        }
0323:                    }
0324:                }
0325:                if (changed)
0326:                    storeOptions(con, TBL_GROUP_OPTIONS, "ID", group.getId(),
0327:                            null, group.getOptions());
0328:                return changed;
0329:            }
0330:
0331:            /*
0332:             * Updates the options of an FxProperty
0333:             * Before the options are updated, they are compared against the options that are
0334:             * already stored in the DB. If there are changes, all present options are deleted
0335:             * in the DB and newly created afterwards from the assignment's option list.
0336:             *
0337:             * @return if the options changed.
0338:             */
0339:
0340:            private boolean updatePropertyOptions(Connection con,
0341:                    FxPropertyEdit prop) throws SQLException {
0342:                boolean changed = false;
0343:                FxPropertyEdit org = new FxPropertyEdit(CacheAdmin
0344:                        .getEnvironment().getProperty(prop.getId()));
0345:                if (org.getOptions().size() != prop.getOptions().size()) {
0346:                    changed = true;
0347:                } else {
0348:                    for (int i = 0; i < org.getOptions().size(); i++) {
0349:                        FxStructureOption orgOpt = org.getOptions().get(i);
0350:                        FxStructureOption propOpt = prop.getOption(orgOpt
0351:                                .getKey());
0352:                        if (!orgOpt.equals(propOpt)) {
0353:                            changed = true;
0354:                            break;
0355:                        }
0356:                    }
0357:                }
0358:                if (changed)
0359:                    storeOptions(con, TBL_PROPERTY_OPTIONS, "ID", prop.getId(),
0360:                            null, prop.getOptions());
0361:                return changed;
0362:            }
0363:
0364:            /*
0365:             * Updates the options of an FxGroupAssignment
0366:             * Before the options are updated, they are compared against the options that are
0367:             * already stored in the DB. If there are changes, all present options are deleted
0368:             * in the DB and newly created afterwards from the assignment's option list.
0369:             *
0370:             * @return if the options changed.
0371:             */
0372:
0373:            private boolean updateGroupAssignmentOptions(Connection con,
0374:                    FxGroupAssignment ga) throws SQLException {
0375:                boolean changed = false;
0376:                FxGroupAssignmentEdit org = ((FxGroupAssignment) CacheAdmin
0377:                        .getEnvironment().getAssignment(ga.getId()))
0378:                        .asEditable();
0379:                FxGroupAssignmentEdit group = ga.asEditable();
0380:                if (org.getOptions().size() != group.getOptions().size()) {
0381:                    changed = true;
0382:                } else {
0383:                    for (int i = 0; i < org.getOptions().size(); i++) {
0384:                        FxStructureOption orgOpt = org.getOptions().get(i);
0385:                        FxStructureOption propOpt = group.getOption(orgOpt
0386:                                .getKey());
0387:                        if (!orgOpt.equals(propOpt)) {
0388:                            changed = true;
0389:                            break;
0390:                        }
0391:                    }
0392:                }
0393:                if (changed)
0394:                    storeOptions(con, TBL_GROUP_OPTIONS, "ID", group.getGroup()
0395:                            .getId(), group.getId(), group.getOptions());
0396:                return changed;
0397:            }
0398:
0399:            /*
0400:             * Updates the options of an FxPropertyAssignment
0401:             * Before the options are updated, they are compared against the options that are
0402:             * already stored in the DB. If there are changes, all present options are deleted
0403:             * in the DB and newly created afterwards from the assignment's option list.
0404:             *
0405:             * @return if the options changed.
0406:             */
0407:
0408:            private boolean updatePropertyAssignmentOptions(Connection con,
0409:                    FxPropertyAssignment original, FxPropertyAssignment modified)
0410:                    throws SQLException {
0411:                boolean changed = false;
0412:                FxPropertyAssignmentEdit org = original.asEditable();
0413:                FxPropertyAssignmentEdit prop = modified.asEditable();
0414:                if (org.getOptions().size() != prop.getOptions().size()) {
0415:                    changed = true;
0416:                } else {
0417:                    for (int i = 0; i < org.getOptions().size(); i++) {
0418:                        FxStructureOption orgOpt = org.getOptions().get(i);
0419:                        FxStructureOption propOpt = prop.getOption(orgOpt
0420:                                .getKey());
0421:                        if (!orgOpt.equals(propOpt)) {
0422:                            changed = true;
0423:                            break;
0424:                        }
0425:                    }
0426:                }
0427:                if (changed)
0428:                    storeOptions(con, TBL_PROPERTY_OPTIONS, "ID", original
0429:                            .getProperty().getId(), original.getId(), prop
0430:                            .getOptions());
0431:                return changed;
0432:            }
0433:
0434:            /*
0435:             * Helper to store options, (the information in brackets expalains how to use this method to store the options
0436:             * for an FxPropertyAssignment)
0437:             *
0438:             * @param con               the DB connection
0439:             * @param table             the table name to store the options (e.g. TBL_PROPERTY_OPTIONS)
0440:             * @param primaryColumn     the column name of the primary key (where the property Id is stored, e.g. ID)
0441:             * @param primaryId         the primary key itself (the property Id, e.g. FxPropertyAssignment.getProperty().getId())
0442:             * @param assignmentId      the foreign key, may be <code>null</code> (the assignment Id, e.g. FxPropertyAssignment.getId())
0443:             * @param options           the option list to store (e.g. FxPropertyAssignmentEdit.getOptions())
0444:             */
0445:            private void storeOptions(Connection con, String table,
0446:                    String primaryColumn, long primaryId, Long assignmentId,
0447:                    List<FxStructureOption> options) throws SQLException {
0448:                PreparedStatement ps = null;
0449:                try {
0450:                    if (assignmentId == null) {
0451:                        ps = con.prepareStatement("DELETE FROM " + table
0452:                                + " WHERE " + primaryColumn
0453:                                + "=? AND ASSID IS NULL");
0454:                    } else {
0455:                        ps = con.prepareStatement("DELETE FROM " + table
0456:                                + " WHERE " + primaryColumn + "=? AND ASSID=?");
0457:                        ps.setLong(2, assignmentId);
0458:                    }
0459:                    ps.setLong(1, primaryId);
0460:                    ps.executeUpdate();
0461:                    if (options == null || options.size() == 0)
0462:                        return;
0463:                    ps.close();
0464:                    ps = con
0465:                            .prepareStatement("INSERT INTO "
0466:                                    + table
0467:                                    + " ("
0468:                                    + primaryColumn
0469:                                    + ",ASSID,OPTKEY,MAYOVERRIDE,OPTVALUE)VALUES(?,?,?,?,?)");
0470:                    for (FxStructureOption option : options) {
0471:                        ps.setLong(1, primaryId);
0472:                        if (assignmentId != null)
0473:                            ps.setLong(2, assignmentId);
0474:                        else
0475:                            ps.setNull(2, java.sql.Types.NUMERIC);
0476:                        ps.setString(3, option.getKey());
0477:                        ps.setBoolean(4, option.isOverrideable());
0478:                        ps.setString(5, option.getValue());
0479:                        ps.addBatch();
0480:                    }
0481:                    ps.executeBatch();
0482:                } finally {
0483:                    if (ps != null)
0484:                        ps.close();
0485:                }
0486:            }
0487:
0488:            /**
0489:             * Helper to process all derived types and derivates of derived types
0490:             *
0491:             * @param assignment the assignment processed
0492:             * @param con        an open and valid connection
0493:             * @param ps         prepared statement being worked with
0494:             * @param sb         StringBuilder
0495:             * @param types      (derived) types to process - will recurse to derived types of these types
0496:             * @throws FxApplicationException on errors
0497:             */
0498:            private void createInheritedAssignments(FxAssignment assignment,
0499:                    Connection con, PreparedStatement ps, StringBuilder sb,
0500:                    List<FxType> types) throws FxApplicationException {
0501:                for (FxType derivedType : types) {
0502:                    if (assignment instanceof  FxPropertyAssignment) {
0503:                        createPropertyAssignment(
0504:                                con,
0505:                                ps,
0506:                                sb,
0507:                                FxPropertyAssignmentEdit
0508:                                        .createNew(
0509:                                                (FxPropertyAssignment) assignment,
0510:                                                derivedType,
0511:                                                assignment.getAlias(),
0512:                                                assignment
0513:                                                        .hasParentGroupAssignment() ? assignment
0514:                                                        .getParentGroupAssignment()
0515:                                                        .getXPath()
0516:                                                        : "/"));
0517:                    } else if (assignment instanceof  FxGroupAssignment) {
0518:                        createGroupAssignment(
0519:                                con,
0520:                                ps,
0521:                                sb,
0522:                                FxGroupAssignmentEdit
0523:                                        .createNew(
0524:                                                (FxGroupAssignment) assignment,
0525:                                                derivedType,
0526:                                                assignment.getAlias(),
0527:                                                assignment
0528:                                                        .hasParentGroupAssignment() ? assignment
0529:                                                        .getParentGroupAssignment()
0530:                                                        .getXPath()
0531:                                                        : "/"), true);
0532:                    }
0533:                    //            if (derivedType.getDerivedTypes().size() > 0)  //one level deeper ...
0534:                    //                _inheritedAssignmentsCreate(assignment, con, ps, sb, derivedType.getDerivedTypes());
0535:                }
0536:            }
0537:
0538:            /**
0539:             * Remove a property, all its assignments and all attributes in contents referencing this property
0540:             *
0541:             * @param propertyId id of the property to remove
0542:             * @throws FxApplicationException on errors
0543:             */
0544:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
0545:            public void removeProperty(long propertyId)
0546:                    throws FxApplicationException {
0547:                //TODO
0548:            }
0549:
0550:            private boolean updateGroup(Connection _con, PreparedStatement ps,
0551:                    StringBuilder sql, FxGroupEdit group)
0552:                    throws FxApplicationException {
0553:                if (sql == null)
0554:                    sql = new StringBuilder(1000);
0555:                Connection con = _con;
0556:                boolean changes = false;
0557:                StringBuilder changesDesc = new StringBuilder(200);
0558:                FxGroup org = CacheAdmin.getEnvironment().getGroup(
0559:                        group.getId());
0560:                try {
0561:                    if (con == null)
0562:                        con = Database.getDbConnection();
0563:                    sql.setLength(0);
0564:
0565:                    //TODO: check valid multiplicity like in updateproperty
0566:                    if (org.getMultiplicity().getMin() != group
0567:                            .getMultiplicity().getMin()
0568:                            || org.getMultiplicity().getMax() != group
0569:                                    .getMultiplicity().getMax()) {
0570:                        if (ps != null)
0571:                            ps.close();
0572:                        ps = con.prepareStatement("UPDATE " + TBL_STRUCT_GROUPS
0573:                                + " SET DEFMINMULT=? ,DEFMAXMULT=? WHERE ID=?");
0574:                        ps.setInt(1, group.getMultiplicity().getMin());
0575:                        ps.setInt(2, group.getMultiplicity().getMax());
0576:                        ps.setLong(3, group.getId());
0577:                        ps.executeUpdate();
0578:                        if (changes)
0579:                            changesDesc.append(',');
0580:                        changesDesc.append("multiplicity=").append(
0581:                                group.getMultiplicity());
0582:                        changes = true;
0583:                    }
0584:
0585:                    if (org.getLabel() != null
0586:                            && !org.getLabel().equals(group.getLabel())
0587:                            || org.getLabel() == null
0588:                            && group.getLabel() != null
0589:                            || org.getHint() != null
0590:                            && !org.getHint().equals(group.getHint())
0591:                            || org.getHint() == null && group.getHint() != null) {
0592:                        Database.storeFxString(new FxString[] {
0593:                                group.getLabel(), group.getHint() }, con,
0594:                                TBL_STRUCT_GROUPS, new String[] {
0595:                                        "DESCRIPTION", "HINT" }, "ID", group
0596:                                        .getId());
0597:                        if (changes)
0598:                            changesDesc.append(',');
0599:                        changesDesc.append("label=").append(group.getLabel())
0600:                                .append(',');
0601:                        changesDesc.append("hint=").append(group.getHint())
0602:                                .append(',');
0603:                        changes = true;
0604:                    }
0605:                    //TODO: thorw exceptipon that this is not supported yet
0606:                    if (!org.getName().equals(group.getName())) {
0607:                        if (ps != null)
0608:                            ps.close();
0609:                        ps = con.prepareStatement("UPDATE " + TBL_STRUCT_GROUPS
0610:                                + " SET NAME=? WHERE ID=?");
0611:                        ps.setString(1, group.getName());
0612:                        ps.setLong(2, group.getId());
0613:                        ps.executeUpdate();
0614:                        if (changes)
0615:                            changesDesc.append(',');
0616:                        changesDesc.append("name=").append(group.getName());
0617:                        changes = true;
0618:                    }
0619:                    if (org.mayOverrideBaseMultiplicity() != group
0620:                            .mayOverrideBaseMultiplicity()) {
0621:                        if (ps != null)
0622:                            ps.close();
0623:                        ps = con.prepareStatement("UPDATE " + TBL_STRUCT_GROUPS
0624:                                + " SET MAYOVERRIDEMULT=? WHERE ID=?");
0625:                        ps.setBoolean(1, group.mayOverrideBaseMultiplicity());
0626:                        ps.setLong(2, group.getId());
0627:                        ps.executeUpdate();
0628:                        if (changes)
0629:                            changesDesc.append(',');
0630:                        changesDesc.append("mayOverrideMultiplicity=").append(
0631:                                group.mayOverrideBaseMultiplicity());
0632:                        changes = true;
0633:                    }
0634:
0635:                    if (updateGroupOptions(con, group)) {
0636:                        changesDesc.append(",options:");
0637:                        List<FxStructureOption> options = group.getOptions();
0638:                        for (FxStructureOption option : options) {
0639:                            changesDesc.append(option.getKey()).append("=")
0640:                                    .append(option.getValue()).append(
0641:                                            " overridable=").append(
0642:                                            option.isOverrideable()).append(
0643:                                            " isSet=").append(option.isSet());
0644:                        }
0645:                        changes = true;
0646:                    }
0647:
0648:                    if (changes) {
0649:                        //TODO: invoke htracker with changeDesc
0650:                    }
0651:
0652:                } catch (SQLException e) {
0653:                    ctx.setRollbackOnly();
0654:                    /*TODO: Determine if this must be checked
0655:                    if (Database.isUniqueConstraintViolation(e))
0656:                        throw new FxEntryExistsException("ex.structure.assignment.property.exists", prop.getAlias(), prop.getXPath());
0657:                     */
0658:                    throw new FxCreateException(LOG, e, "ex.db.sqlError", e
0659:                            .getMessage());
0660:                } finally {
0661:                    if (_con == null) {
0662:                        Database.closeObjects(AssignmentEngineBean.class, con,
0663:                                ps);
0664:                    }
0665:                }
0666:                return changes;
0667:            }
0668:
0669:            /**
0670:             * {@inheritDoc}
0671:             */
0672:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
0673:            public long createGroup(FxGroupEdit group, String parentXPath)
0674:                    throws FxApplicationException {
0675:                return createGroup(FxType.ROOT_ID, group, parentXPath);
0676:            }
0677:
0678:            /**
0679:             * {@inheritDoc}
0680:             */
0681:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
0682:            public long createGroup(long typeId, FxGroupEdit group,
0683:                    String parentXPath) throws FxApplicationException {
0684:                FxPermissionUtils.checkRole(FxContext.get().getTicket(),
0685:                        Role.StructureManagement);
0686:                Connection con = null;
0687:                PreparedStatement ps = null;
0688:                StringBuilder sql = new StringBuilder(2000);
0689:                long newGroupId;
0690:                long newAssignmentId;
0691:                try {
0692:                    parentXPath = parentXPath.toUpperCase();
0693:                    FxType type = CacheAdmin.getEnvironment().getType(typeId);
0694:                    FxAssignment tmp = type.getAssignment(parentXPath);
0695:                    if (tmp != null && tmp instanceof  FxPropertyAssignment)
0696:                        throw new FxInvalidParameterException(
0697:                                "ex.structure.assignment.noGroup", parentXPath);
0698:                    //parentXPath is valid, create the group, then assign it to root
0699:                    newGroupId = seq.getId(SequencerEngine.System.TYPEGROUP);
0700:                    con = Database.getDbConnection();
0701:                    //create group
0702:                    sql
0703:                            .append("INSERT INTO ")
0704:                            .append(TBL_STRUCT_GROUPS)
0705:                            .append(
0706:                                    "(ID,NAME,DEFMINMULT,DEFMAXMULT,MAYOVERRIDEMULT)VALUES(?,?,?,?,?)");
0707:                    ps = con.prepareStatement(sql.toString());
0708:                    ps.setLong(1, newGroupId);
0709:                    ps.setString(2, group.getName());
0710:                    ps.setInt(3, group.getMultiplicity().getMin());
0711:                    ps.setInt(4, group.getMultiplicity().getMax());
0712:                    ps.setBoolean(5, group.mayOverrideBaseMultiplicity());
0713:                    ps.executeUpdate();
0714:                    ps.close();
0715:                    sql.setLength(0);
0716:                    Database.storeFxString(new FxString[] { group.getLabel(),
0717:                            group.getHint() }, con, TBL_STRUCT_GROUPS,
0718:                            new String[] { "DESCRIPTION", "HINT" }, "ID",
0719:                            newGroupId);
0720:                    //calc new position
0721:                    sql.append("SELECT COALESCE(MAX(POS)+1,0) FROM ").append(
0722:                            TBL_STRUCT_ASSIGNMENTS).append(
0723:                            " WHERE PARENTGROUP=? AND TYPEDEF=?");
0724:                    ps = con.prepareStatement(sql.toString());
0725:                    ps.setLong(1, (tmp == null ? FxAssignment.NO_PARENT : tmp
0726:                            .getId()));
0727:                    ps.setLong(2, typeId);
0728:                    ResultSet rs = ps.executeQuery();
0729:                    long pos = 0;
0730:                    if (rs != null && rs.next()) {
0731:                        if (rs.wasNull())
0732:                            pos = 0;
0733:                        else
0734:                            pos = rs.getLong(1);
0735:                    }
0736:                    ps.close();
0737:                    sql.setLength(0);
0738:                    //create root assignment
0739:                    sql.append("INSERT INTO ")
0740:                            .append(TBL_STRUCT_ASSIGNMENTS)
0741:                            .
0742:                            //               1  2     3       4       5       6       7       8   9     10     11   12          13     14
0743:                            append(
0744:                                    "(ID,ATYPE,ENABLED,TYPEDEF,MINMULT,MAXMULT,DEFMULT,POS,XPATH,XALIAS,BASE,PARENTGROUP,AGROUP,GROUPMODE)"
0745:                                            + "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
0746:                    ps = con.prepareStatement(sql.toString());
0747:                    newAssignmentId = seq
0748:                            .getId(SequencerEngine.System.ASSIGNMENT);
0749:                    ps.setLong(1, newAssignmentId);
0750:                    ps.setInt(2, FxAssignment.TYPE_GROUP);
0751:                    ps.setBoolean(3, true);
0752:                    ps.setLong(4, typeId);
0753:                    ps.setInt(5, group.getMultiplicity().getMin());
0754:                    ps.setInt(6, group.getMultiplicity().getMax());
0755:                    if (group.getMultiplicity().isValid(
0756:                            group.getAssignmentDefaultMultiplicity())) {
0757:                        ps.setInt(7, group.getAssignmentDefaultMultiplicity());
0758:                    } else {
0759:                        //default is min(min,1).
0760:                        ps.setInt(7,
0761:                                group.getMultiplicity().getMin() > 1 ? group
0762:                                        .getMultiplicity().getMin() : 1);
0763:                    }
0764:                    ps.setLong(8, pos);
0765:                    if (parentXPath == null || "/".equals(parentXPath))
0766:                        parentXPath = "";
0767:                    ps.setString(9, type.getName() + parentXPath + "/"
0768:                            + group.getName());
0769:                    ps.setString(10, group.getName());
0770:                    ps.setNull(11, java.sql.Types.NUMERIC);
0771:                    ps.setLong(12, (tmp == null ? FxAssignment.NO_PARENT : tmp
0772:                            .getId()));
0773:                    ps.setLong(13, newGroupId);
0774:                    ps.setInt(14, group.getAssignmentGroupMode().getId());
0775:                    ps.executeUpdate();
0776:                    Database.storeFxString(new FxString[] { group.getLabel(),
0777:                            group.getHint() }, con, TBL_STRUCT_ASSIGNMENTS,
0778:                            new String[] { "DESCRIPTION", "HINT" }, "ID",
0779:                            newAssignmentId);
0780:                    StructureLoader.reload(con);
0781:                    htracker.track(type, "history.assignment.createGroup",
0782:                            group.getName(), type.getId(), type.getName());
0783:                    createInheritedAssignments(CacheAdmin.getEnvironment()
0784:                            .getAssignment(newAssignmentId), con, ps, sql, type
0785:                            .getDerivedTypes());
0786:                } catch (FxNotFoundException e) {
0787:                    ctx.setRollbackOnly();
0788:                    throw new FxCreateException(e);
0789:                } catch (FxLoadException e) {
0790:                    ctx.setRollbackOnly();
0791:                    throw new FxCreateException(e);
0792:                } catch (SQLException e) {
0793:                    final boolean uniqueConstraintViolation = Database
0794:                            .isUniqueConstraintViolation(e);
0795:                    ctx.setRollbackOnly();
0796:                    if (uniqueConstraintViolation)
0797:                        throw new FxEntryExistsException(
0798:                                "ex.structure.group.exists", group.getName(),
0799:                                (parentXPath.length() == 0 ? "/" : parentXPath));
0800:                    throw new FxCreateException(LOG, e, "ex.db.sqlError", e
0801:                            .getMessage());
0802:                } catch (FxCacheException e) {
0803:                    ctx.setRollbackOnly();
0804:                    throw new FxCreateException(e, "ex.cache", e.getMessage());
0805:                } finally {
0806:                    Database.closeObjects(AssignmentEngineBean.class, con, ps);
0807:                }
0808:                return newAssignmentId;
0809:            }
0810:
0811:            /**
0812:             * Removes a group and all subgroups and properties assigned to it as well as all references in content instances
0813:             *
0814:             * @param groupId id of the group to remove
0815:             * @throws FxApplicationException on errors
0816:             */
0817:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
0818:            public void removeGroup(long groupId) throws FxApplicationException {
0819:                //TODO
0820:            }
0821:
0822:            /**
0823:             * {@inheritDoc}
0824:             */
0825:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
0826:            public long save(FxAssignment assignment,
0827:                    boolean createSubAssignments) throws FxApplicationException {
0828:                FxPermissionUtils.checkRole(FxContext.get().getTicket(),
0829:                        Role.StructureManagement);
0830:                long returnId;
0831:                boolean reload = false;
0832:                if (assignment instanceof  FxPropertyAssignmentEdit) {
0833:                    if (((FxPropertyAssignmentEdit) assignment).isNew()) {
0834:                        returnId = createPropertyAssignment(null, null, null,
0835:                                (FxPropertyAssignmentEdit) assignment);
0836:                    } else {
0837:                        returnId = assignment.getId();
0838:                        try {
0839:                            reload = updatePropertyAssignment(null, null, null,
0840:                                    null, (FxPropertyAssignmentEdit) assignment);
0841:                        } catch (FxLoadException e) {
0842:                            ctx.setRollbackOnly();
0843:                            throw new FxUpdateException(e);
0844:                        } catch (FxNotFoundException e) {
0845:                            ctx.setRollbackOnly();
0846:                            throw new FxUpdateException(e);
0847:                        }
0848:                    }
0849:
0850:                } else if (assignment instanceof  FxGroupAssignmentEdit) {
0851:                    if (((FxGroupAssignmentEdit) assignment).isNew()) {
0852:                        returnId = createGroupAssignment(null, null, null,
0853:                                (FxGroupAssignmentEdit) assignment,
0854:                                createSubAssignments);
0855:                    } else {
0856:                        returnId = assignment.getId();
0857:                        try {
0858:                            reload = updateGroupAssignment(null, null, null,
0859:                                    (FxGroupAssignmentEdit) assignment);
0860:                        } catch (FxLoadException e) {
0861:                            ctx.setRollbackOnly();
0862:                            throw new FxUpdateException(e);
0863:                        } catch (FxNotFoundException e) {
0864:                            ctx.setRollbackOnly();
0865:                            throw new FxUpdateException(e);
0866:                        }
0867:                    }
0868:                } else
0869:                    throw new FxInvalidParameterException("ASSIGNMENT",
0870:                            "ex.structure.assignment.noEditAssignment");
0871:                try {
0872:                    if (reload) {
0873:                        StructureLoader.reload(null);
0874:                        //clear instance cache
0875:                        CacheAdmin.expireCachedContents();
0876:                    }
0877:                } catch (FxCacheException e) {
0878:                    ctx.setRollbackOnly();
0879:                    throw new FxCreateException(e, "ex.cache", e.getMessage());
0880:                } catch (FxLoadException e) {
0881:                    ctx.setRollbackOnly();
0882:                    throw new FxCreateException(e);
0883:                }
0884:                return returnId;
0885:            }
0886:
0887:            private boolean updateGroupAssignment(Connection _con,
0888:                    PreparedStatement ps, StringBuilder sql,
0889:                    FxGroupAssignmentEdit group) throws FxApplicationException {
0890:                if (sql == null)
0891:                    sql = new StringBuilder(1000);
0892:                if (group.isNew())
0893:                    throw new FxInvalidParameterException(
0894:                            "ex.structure.assignment.update.new", group
0895:                                    .getXPath());
0896:                Connection con = _con;
0897:                boolean changes = false;
0898:                StringBuilder changesDesc = new StringBuilder(200);
0899:                FxGroupAssignment org = (FxGroupAssignment) CacheAdmin
0900:                        .getEnvironment().getAssignment(group.getId());
0901:                try {
0902:                    if (con == null)
0903:                        con = Database.getDbConnection();
0904:                    sql.setLength(0);
0905:                    if (org.isEnabled() != group.isEnabled()) {
0906:                        if (changes)
0907:                            changesDesc.append(',');
0908:                        changesDesc.append("enabled=")
0909:                                .append(group.isEnabled());
0910:                        //apply for all child groups and properties as well!
0911:                        if (org.getAssignments().size() > 0)
0912:                            changesDesc.append(", ").append(
0913:                                    group.isEnabled() ? "en" : "dis").append(
0914:                                    "abled child assignments: ");
0915:                        for (FxAssignment as : org.getAssignments()) {
0916:                            changesDesc.append(as.getXPath()).append(',');
0917:                        }
0918:                        if (changesDesc.charAt(changesDesc.length() - 1) == ',')
0919:                            changesDesc.deleteCharAt(changesDesc.length() - 1);
0920:                        if (!group.isEnabled())
0921:                            removeAssignment(org.getId(), true, false, true);
0922:                        else {
0923:                            StringBuilder affectedAssignment = new StringBuilder(
0924:                                    500);
0925:                            affectedAssignment.append(org.getId());
0926:                            for (FxAssignment as : org.getAllChildAssignments())
0927:                                affectedAssignment.append(",").append(
0928:                                        as.getId());
0929:                            if (ps != null)
0930:                                ps.close();
0931:                            ps = con.prepareStatement("UPDATE "
0932:                                    + TBL_STRUCT_ASSIGNMENTS
0933:                                    + " SET ENABLED=? WHERE ID IN ("
0934:                                    + affectedAssignment + ")");
0935:                            ps.setBoolean(1, true);
0936:                            ps.executeUpdate();
0937:                        }
0938:                        changes = true;
0939:                    }
0940:
0941:                    //TODO: check if multiplicity is in valid ranges
0942:                    if (org.getDefaultMultiplicity() != group
0943:                            .getDefaultMultiplicity()) {
0944:                        if (ps != null)
0945:                            ps.close();
0946:                        ps = con.prepareStatement("UPDATE "
0947:                                + TBL_STRUCT_ASSIGNMENTS
0948:                                + " SET DEFMULT=? WHERE ID=?");
0949:                        ps.setInt(1, group.getDefaultMultiplicity());
0950:                        ps.setLong(2, group.getId());
0951:                        ps.executeUpdate();
0952:                        if (changes)
0953:                            changesDesc.append(',');
0954:                        changesDesc.append("defaultMultiplicity=").append(
0955:                                group.getDefaultMultiplicity());
0956:                        changes = true;
0957:                    }
0958:
0959:                    //TODO: must not be changed
0960:                    if (org.getAssignedType().getId() != group
0961:                            .getAssignedType().getId()) {
0962:                        if (ps != null)
0963:                            ps.close();
0964:                        ps = con.prepareStatement("UPDATE "
0965:                                + TBL_STRUCT_ASSIGNMENTS
0966:                                + " SET TYPEDEF=? WHERE ID=?");
0967:                        ps.setLong(1, group.getAssignedType().getId());
0968:                        ps.setLong(2, group.getId());
0969:                        ps.executeUpdate();
0970:                        if (changes)
0971:                            changesDesc.append(',');
0972:                        changesDesc.append("assignedType=").append(
0973:                                group.getAssignedType());
0974:                        changes = true;
0975:                    }
0976:                    //siehe prop
0977:                    if (org.getMultiplicity().getMin() != group
0978:                            .getMultiplicity().getMin()
0979:                            || org.getMultiplicity().getMax() != group
0980:                                    .getMultiplicity().getMax()) {
0981:                        if (ps != null)
0982:                            ps.close();
0983:                        ps = con.prepareStatement("UPDATE "
0984:                                + TBL_STRUCT_ASSIGNMENTS
0985:                                + " SET MINMULT=? ,MAXMULT=? WHERE ID=?");
0986:                        ps.setInt(1, group.getMultiplicity().getMin());
0987:                        ps.setInt(2, group.getMultiplicity().getMax());
0988:                        ps.setLong(3, group.getId());
0989:                        ps.executeUpdate();
0990:                        if (changes)
0991:                            changesDesc.append(',');
0992:                        changesDesc.append("multiplicity=").append(
0993:                                group.getMultiplicity());
0994:                        changes = true;
0995:                    }
0996:                    if (org.getPosition() != group.getPosition()) {
0997:                        int finalPos = setAssignmentPosition(con,
0998:                                group.getId(), group.getPosition());
0999:                        if (changes)
1000:                            changesDesc.append(',');
1001:                        changesDesc.append("position=").append(finalPos);
1002:                        changes = true;
1003:                    }
1004:                    if (!org.getXPath().equals(group.getXPath())
1005:                            || !org.getAlias().equals(group.getAlias())) {
1006:                        if (!XPathElement.isValidXPath(XPathElement
1007:                                .stripType(group.getXPath()))
1008:                                || group.getAlias().equals(
1009:                                        XPathElement.lastElement(
1010:                                                XPathElement.stripType(org
1011:                                                        .getXPath()))
1012:                                                .getAlias()))
1013:                            throw new FxUpdateException(
1014:                                    "ex.structure.assignment.noXPath");
1015:                        try {
1016:                            //avoid duplicates
1017:                            org.getAssignedType().getAssignment(
1018:                                    group.getXPath());
1019:                            throw new FxUpdateException(
1020:                                    "ex.structure.assignment.exists", group
1021:                                            .getXPath(), group
1022:                                            .getAssignedType().getName());
1023:                        } catch (FxNotFoundException e) {
1024:                            //expected
1025:                        }
1026:                        //TODO: make sure just the alias changed
1027:                        if (ps != null)
1028:                            ps.close();
1029:                        ps = con.prepareStatement("UPDATE "
1030:                                + TBL_STRUCT_ASSIGNMENTS
1031:                                + " SET XPATH=?, XALIAS=? WHERE ID=?");
1032:                        ps.setString(1, group.getXPath());
1033:                        ps.setString(2, group.getAlias());
1034:                        ps.setLong(3, group.getId());
1035:                        ps.executeUpdate();
1036:                        ContentStorage storage = StorageManager
1037:                                .getContentStorage(TypeStorageMode.Hierarchical);
1038:                        storage.updateXPath(con, group.getId(), XPathElement
1039:                                .stripType(org.getXPath()), XPathElement
1040:                                .stripType(group.getXPath()));
1041:                        //update all child assignments
1042:                        ps.close();
1043:                        ps = con.prepareStatement("UPDATE "
1044:                                + TBL_STRUCT_ASSIGNMENTS
1045:                                + " SET XPATH=? WHERE ID=?");
1046:                        for (FxAssignment child : org.getAllChildAssignments()) {
1047:                            ps.setString(1, group.getXPath()
1048:                                    + child.getXPath().substring(
1049:                                            org.getXPath().length()));
1050:                            ps.setLong(2, child.getId());
1051:                            ps.executeUpdate();
1052:                            storage.updateXPath(con, child.getId(),
1053:                                    XPathElement.stripType(child.getXPath()),
1054:                                    XPathElement.stripType(group.getXPath()
1055:                                            + child.getXPath().substring(
1056:                                                    org.getXPath().length())));
1057:                        }
1058:                        if (changes)
1059:                            changesDesc.append(',');
1060:                        changesDesc.append("xPath=").append(group.getXPath())
1061:                                .append(",alias=").append(group.getAlias());
1062:                        changes = true;
1063:                    }
1064:
1065:                    //TODO:may not be changed, throw exception
1066:                    /*if (org.getBaseAssignmentId() != group.getBaseAssignmentId()) {
1067:                        if (ps != null) ps.close();
1068:                        ps = con.prepareStatement("UPDATE " + TBL_STRUCT_ASSIGNMENTS + " SET BASE=? WHERE ID=?");
1069:                        ps.setLong(1, group.getBaseAssignmentId());
1070:                        ps.setLong(2, group.getId());
1071:                        ps.executeUpdate();
1072:                        if (changes)
1073:                            changesDesc.append(',');
1074:                        changesDesc.append("baseAssignment=").append(group.getBaseAssignmentId());
1075:                        changes = true;
1076:                    }*/
1077:
1078:                    //TODO:may not be changed, throw exception
1079:                    /*if (org.getParentGroupAssignment() != null &&
1080:                            !org.getParentGroupAssignment().equals(group.getParentGroupAssignment()) ||
1081:                            group.getParentGroupAssignment() != null &&
1082:                                    !group.getParentGroupAssignment().equals(org.getParentGroupAssignment())) {
1083:                        if (ps != null) ps.close();
1084:                        ps = con.prepareStatement("UPDATE " + TBL_STRUCT_ASSIGNMENTS + " SET PARENTGROUP=? WHERE ID=?");
1085:                        if (group.getParentGroupAssignment() != null)
1086:                            ps.setLong(1, group.getParentGroupAssignment().getId());
1087:                        else
1088:                            ps.setLong(1, FxAssignment.NO_PARENT);
1089:                        ps.setLong(2, group.getId());
1090:                        ps.executeUpdate();
1091:                        if (changes)
1092:                            changesDesc.append(',');
1093:                        changesDesc.append("parentGroupAssignment=").append(group.getParentGroupAssignment());
1094:                        changes = true;
1095:                    }*/
1096:
1097:                    if (org.getLabel() != null
1098:                            && !org.getLabel().equals(group.getLabel())
1099:                            || org.getLabel() == null
1100:                            && group.getLabel() != null
1101:                            || org.getHint() != null
1102:                            && !org.getHint().equals(group.getHint())
1103:                            || org.getHint() == null && group.getHint() != null) {
1104:                        Database.storeFxString(new FxString[] {
1105:                                group.getLabel(), group.getHint() }, con,
1106:                                TBL_STRUCT_ASSIGNMENTS, new String[] {
1107:                                        "DESCRIPTION", "HINT" }, "ID", group
1108:                                        .getId());
1109:                        if (changes)
1110:                            changesDesc.append(',');
1111:                        changesDesc.append("label=").append(group.getLabel())
1112:                                .append(',');
1113:                        changesDesc.append("hint=").append(group.getHint())
1114:                                .append(',');
1115:                        changes = true;
1116:                    }
1117:
1118:                    //update SystemInternal flag, this is a one way function, so it can only be set, but not reset!!
1119:                    if (!org.isSystemInternal() && group.isSystemInternal()
1120:                            && FxContext.get().getTicket().isGlobalSupervisor()) {
1121:                        if (ps != null)
1122:                            ps.close();
1123:                        ps = con.prepareStatement("UPDATE "
1124:                                + TBL_STRUCT_ASSIGNMENTS
1125:                                + " SET SYSINTERNAL=? WHERE ID=?");
1126:                        ps.setBoolean(1, group.isSystemInternal());
1127:                        ps.setLong(2, group.getId());
1128:                        ps.executeUpdate();
1129:                        if (changes)
1130:                            changesDesc.append(',');
1131:                        changesDesc.append("systemInternal=").append(
1132:                                group.isSystemInternal());
1133:                        changes = true;
1134:                    }
1135:
1136:                    //TODO: only make changable if no instances of this group exist, or if the mode is changed from one.of to any.of
1137:                    if (org.getMode().getId() != group.getMode().getId()) {
1138:                        if (ps != null)
1139:                            ps.close();
1140:                        ps = con.prepareStatement("UPDATE "
1141:                                + TBL_STRUCT_ASSIGNMENTS
1142:                                + " SET GROUPMODE=? WHERE ID=?");
1143:                        ps.setLong(1, group.getMode().getId());
1144:                        ps.setLong(2, group.getId());
1145:                        ps.executeUpdate();
1146:                        if (changes)
1147:                            changesDesc.append(',');
1148:                        changesDesc.append("groupMode=").append(
1149:                                group.getMode().getId());
1150:                        changes = true;
1151:                    }
1152:
1153:                    if (updateGroupAssignmentOptions(con, group)) {
1154:                        changesDesc.append(",options:");
1155:                        List<FxStructureOption> options = group.getOptions();
1156:                        for (FxStructureOption option : options) {
1157:                            changesDesc.append(option.getKey()).append("=")
1158:                                    .append(option.getValue()).append(
1159:                                            " overridable=").append(
1160:                                            option.isOverrideable()).append(
1161:                                            " isSet=").append(option.isSet());
1162:                        }
1163:                        changes = true;
1164:                    }
1165:                    //TODO: compare all possible modifications
1166:                    if (changes)
1167:                        htracker.track(group.getAssignedType(),
1168:                                "history.assignment.updateGroupAssignment",
1169:                                group.getXPath(), group.getAssignedType()
1170:                                        .getId(), group.getAssignedType()
1171:                                        .getName(), group.getGroup().getId(),
1172:                                group.getGroup().getName(), changesDesc
1173:                                        .toString());
1174:
1175:                } catch (SQLException e) {
1176:                    final boolean uniqueConstraintViolation = Database
1177:                            .isUniqueConstraintViolation(e);
1178:                    ctx.setRollbackOnly();
1179:                    if (uniqueConstraintViolation)
1180:                        throw new FxEntryExistsException(
1181:                                "ex.structure.assignment.group.exists", group
1182:                                        .getAlias(), group.getXPath());
1183:                    throw new FxCreateException(LOG, e, "ex.db.sqlError", e
1184:                            .getMessage());
1185:                } finally {
1186:                    if (_con == null) {
1187:                        Database.closeObjects(AssignmentEngineBean.class, con,
1188:                                ps);
1189:                    }
1190:                }
1191:                return changes;
1192:            }
1193:
1194:            /**
1195:             * Set an assignments position, updating positions of all assignments in the same hierarchy level
1196:             *
1197:             * @param con          an open and valid connection
1198:             * @param assignmentId the id of the assignment with the desired position
1199:             * @param position     desired position
1200:             * @return the position that "really" was assigned
1201:             * @throws FxUpdateException on errors
1202:             */
1203:            private int setAssignmentPosition(Connection con,
1204:                    long assignmentId, int position) throws FxUpdateException {
1205:                if (position < 0)
1206:                    position = 0;
1207:                PreparedStatement ps = null, ps2 = null;
1208:                int retPosition = position;
1209:                try {
1210:                    ps = con
1211:                            .prepareStatement("SELECT TYPEDEF, PARENTGROUP, POS, SYSINTERNAL FROM "
1212:                                    + TBL_STRUCT_ASSIGNMENTS + " WHERE ID=?");
1213:                    ps.setLong(1, assignmentId);
1214:                    ResultSet rs = ps.executeQuery();
1215:                    if (rs == null || !rs.next())
1216:                        return position; //no record exists
1217:                    long typeId = rs.getLong(1);
1218:                    long parentGroupId = rs.getLong(2);
1219:                    int orgPos = rs.getInt(3);
1220:                    boolean sysinternal = rs.getBoolean(4);
1221:                    if (orgPos == position)
1222:                        return retPosition; //no need to change anything
1223:
1224:                    if (!sysinternal
1225:                            && parentGroupId == FxAssignment.NO_PARENT
1226:                            && position < CacheAdmin.getEnvironment()
1227:                                    .getSystemInternalRootPropertyAssignments()
1228:                                    .size()) {
1229:                        //adjust position to be above the sysinternal properties if connected to the root group
1230:                        position += CacheAdmin.getEnvironment()
1231:                                .getSystemInternalRootPropertyAssignments()
1232:                                .size();
1233:                    }
1234:
1235:                    //move all positions in a range of 10000+ without gaps
1236:                    ps.close();
1237:                    ps = con
1238:                            .prepareStatement("SELECT ID FROM "
1239:                                    + TBL_STRUCT_ASSIGNMENTS
1240:                                    + " WHERE TYPEDEF=? AND PARENTGROUP=? ORDER BY POS");
1241:                    ps.setLong(1, typeId);
1242:                    ps.setLong(2, parentGroupId);
1243:                    rs = ps.executeQuery();
1244:                    ps2 = con.prepareStatement("UPDATE "
1245:                            + TBL_STRUCT_ASSIGNMENTS + " SET POS=? WHERE ID=?");
1246:                    int counter = 10000;
1247:                    while (rs != null && rs.next()) {
1248:                        ps2.setInt(1, counter++);
1249:                        ps2.setLong(2, rs.getLong(1));
1250:                        ps2.addBatch();
1251:                    }
1252:                    ps2.executeBatch();
1253:
1254:                    ps.close();
1255:                    ps = con
1256:                            .prepareStatement("SELECT ID FROM "
1257:                                    + TBL_STRUCT_ASSIGNMENTS
1258:                                    + " WHERE TYPEDEF=? AND PARENTGROUP=? AND POS>=? AND ID<>? ORDER BY POS");
1259:                    ps.setLong(1, typeId);
1260:                    ps.setLong(2, parentGroupId);
1261:                    ps.setInt(3, 10000);
1262:                    ps.setLong(4, assignmentId);
1263:                    rs = ps.executeQuery();
1264:                    int currPos = 0;
1265:                    boolean written = false;
1266:                    while (rs != null && rs.next()) {
1267:                        ps2.setInt(1, currPos);
1268:                        if (!written && currPos == position) {
1269:                            written = true;
1270:                            retPosition = currPos;
1271:                            ps2.setLong(2, assignmentId);
1272:                            ps2.addBatch();
1273:                            ps2.setInt(1, ++currPos);
1274:                        }
1275:                        ps2.setLong(2, rs.getLong(1));
1276:                        ps2.addBatch();
1277:                        currPos++;
1278:                    }
1279:                    if (!written) {
1280:                        //last element
1281:                        retPosition = currPos;
1282:                        ps2.setInt(1, currPos);
1283:                        ps2.setLong(2, assignmentId);
1284:                        ps2.addBatch();
1285:                    }
1286:                    ps2.executeBatch();
1287:                } catch (SQLException e) {
1288:                    throw new FxUpdateException(LOG, e, "ex.db.sqlError", e
1289:                            .getMessage());
1290:                } finally {
1291:                    try {
1292:                        if (ps != null)
1293:                            ps.close();
1294:                    } catch (SQLException e) {
1295:                        //ignore
1296:                    }
1297:                    try {
1298:                        if (ps2 != null)
1299:                            ps2.close();
1300:                    } catch (SQLException e) {
1301:                        //ignore
1302:                    }
1303:                }
1304:                return retPosition;
1305:            }
1306:
1307:            private long createGroupAssignment(Connection _con,
1308:                    PreparedStatement ps, StringBuilder sql,
1309:                    FxGroupAssignmentEdit group, boolean createSubAssignments)
1310:                    throws FxApplicationException {
1311:                if (sql == null)
1312:                    sql = new StringBuilder(1000);
1313:                if (!group.isNew())
1314:                    throw new FxInvalidParameterException(
1315:                            "ex.structure.assignment.create.existing", group
1316:                                    .getXPath());
1317:                Connection con = _con;
1318:                long newAssignmentId;
1319:                try {
1320:                    if (con == null)
1321:                        con = Database.getDbConnection();
1322:                    FxGroupAssignment this GroupAssignment;
1323:                    String XPath;
1324:                    if (!group.getXPath().startsWith(
1325:                            group.getAssignedType().getName())) {
1326:                        if (group.getAlias() != null)
1327:                            XPath = XPathElement.buildXPath(false, group
1328:                                    .getAssignedType().getName(), group
1329:                                    .getXPath());
1330:                        else
1331:                            XPath = "/";
1332:                    } else
1333:                        XPath = group.getXPath();
1334:                    if (group.getAlias() != null) {
1335:                        sql.setLength(0);
1336:                        sql.append("INSERT INTO ")
1337:                                .append(TBL_STRUCT_ASSIGNMENTS)
1338:                                .
1339:                                //               1  2     3       4       5       6       7       8   9     10     11   12          13     14          15
1340:                                append(
1341:                                        "(ID,ATYPE,ENABLED,TYPEDEF,MINMULT,MAXMULT,DEFMULT,POS,XPATH,XALIAS,BASE,PARENTGROUP,AGROUP,SYSINTERNAL,GROUPMODE)"
1342:                                                + "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
1343:                        if (ps != null)
1344:                            ps.close();
1345:                        ps = con.prepareStatement(sql.toString());
1346:                        newAssignmentId = seq
1347:                                .getId(SequencerEngine.System.ASSIGNMENT);
1348:                        ps.setLong(1, newAssignmentId);
1349:                        ps.setInt(2, FxAssignment.TYPE_GROUP);
1350:                        ps.setBoolean(3, group.isEnabled());
1351:                        ps.setLong(4, group.getAssignedType().getId());
1352:                        ps.setInt(5, group.getMultiplicity().getMin());
1353:                        ps.setInt(6, group.getMultiplicity().getMax());
1354:                        ps.setInt(7, group.getDefaultMultiplicity());
1355:                        int position = getValidPosition(con, sql, group
1356:                                .getPosition(),
1357:                                group.getAssignedType().getId(), group
1358:                                        .getParentGroupAssignment());
1359:                        ps.setInt(8, position);
1360:                        ps.setString(9, XPath);
1361:                        ps.setString(10, group.getAlias());
1362:                        ps.setLong(11, group.getBaseAssignmentId());
1363:                        ps
1364:                                .setLong(
1365:                                        12,
1366:                                        group.getParentGroupAssignment() == null ? FxAssignment.NO_PARENT
1367:                                                : group
1368:                                                        .getParentGroupAssignment()
1369:                                                        .getId());
1370:                        ps.setLong(13, group.getGroup().getId());
1371:                        ps.setBoolean(14, group.isSystemInternal());
1372:                        ps.setInt(15, group.getMode().getId());
1373:                        ps.executeUpdate();
1374:                        Database.storeFxString(new FxString[] {
1375:                                group.getLabel(), group.getHint() }, con,
1376:                                TBL_STRUCT_ASSIGNMENTS, new String[] {
1377:                                        "DESCRIPTION", "HINT" }, "ID",
1378:                                newAssignmentId);
1379:                        this GroupAssignment = new FxGroupAssignment(
1380:                                newAssignmentId, true, group.getAssignedType(),
1381:                                group.getAlias(), XPath, position, group
1382:                                        .getMultiplicity(), group
1383:                                        .getDefaultMultiplicity(), group
1384:                                        .getParentGroupAssignment(), group
1385:                                        .getBaseAssignmentId(), group
1386:                                        .getLabel(), group.getHint(), group
1387:                                        .getGroup(), group.getMode(), null);
1388:                        setAssignmentPosition(con, group.getId(), group
1389:                                .getPosition());
1390:                    } else {
1391:                        this GroupAssignment = null;
1392:                        newAssignmentId = FxAssignment.NO_PARENT;
1393:                    }
1394:                    htracker.track(group.getAssignedType(),
1395:                            "history.assignment.createGroupAssignment", XPath,
1396:                            group.getAssignedType().getId(), group
1397:                                    .getAssignedType().getName(), group
1398:                                    .getGroup().getId(), group.getGroup()
1399:                                    .getName());
1400:                    if (group.getBaseAssignmentId() != FxAssignment.ROOT_BASE
1401:                            && createSubAssignments) {
1402:                        FxGroupAssignment baseGroup = (FxGroupAssignment) CacheAdmin
1403:                                .getEnvironment().getAssignment(
1404:                                        group.getBaseAssignmentId());
1405:                        for (FxGroupAssignment ga : baseGroup
1406:                                .getAssignedGroups()) {
1407:                            FxGroupAssignmentEdit gae = new FxGroupAssignmentEdit(
1408:                                    ga);
1409:                            gae.setEnabled(group.isEnabled());
1410:                            createGroupAssignment(con, null, sql,
1411:                                    FxGroupAssignmentEdit.createNew(gae, group
1412:                                            .getAssignedType(), ga.getAlias(),
1413:                                            XPath, this GroupAssignment),
1414:                                    createSubAssignments);
1415:                        }
1416:                        for (FxPropertyAssignment pa : baseGroup
1417:                                .getAssignedProperties()) {
1418:                            FxPropertyAssignmentEdit pae = new FxPropertyAssignmentEdit(
1419:                                    pa);
1420:                            pae.setEnabled(group.isEnabled());
1421:                            createPropertyAssignment(con, null, sql,
1422:                                    FxPropertyAssignmentEdit.createNew(pae,
1423:                                            group.getAssignedType(), pa
1424:                                                    .getAlias(), XPath,
1425:                                            this GroupAssignment));
1426:                        }
1427:                    }
1428:                    try {
1429:                        StructureLoader.reload(con);
1430:                    } catch (FxCacheException e) {
1431:                        ctx.setRollbackOnly();
1432:                        throw new FxCreateException(e, "ex.cache", e
1433:                                .getMessage());
1434:                    }
1435:                    createInheritedAssignments(CacheAdmin.getEnvironment()
1436:                            .getAssignment(newAssignmentId), con, ps, sql,
1437:                            group.getAssignedType().getDerivedTypes());
1438:                } catch (SQLException e) {
1439:                    final boolean uniqueConstraintViolation = Database
1440:                            .isUniqueConstraintViolation(e);
1441:                    ctx.setRollbackOnly();
1442:                    if (uniqueConstraintViolation)
1443:                        throw new FxEntryExistsException(
1444:                                "ex.structure.assignment.group.exists", group
1445:                                        .getAlias(), group.getXPath());
1446:                    throw new FxCreateException(LOG, e, "ex.db.sqlError", e
1447:                            .getMessage());
1448:                } catch (FxNotFoundException e) {
1449:                    throw new FxCreateException(e);
1450:                } finally {
1451:                    if (_con == null) {
1452:                        Database.closeObjects(AssignmentEngineBean.class, con,
1453:                                ps);
1454:                    }
1455:                }
1456:                return newAssignmentId;
1457:            }
1458:
1459:            private boolean updateProperty(Connection _con,
1460:                    PreparedStatement ps, StringBuilder sql, FxPropertyEdit prop)
1461:                    throws FxApplicationException {
1462:                if (sql == null)
1463:                    sql = new StringBuilder(1000);
1464:                if (prop.isNew())
1465:                    throw new FxInvalidParameterException(
1466:                            "ex.structure.property.update.new", prop.getName());
1467:                Connection con = _con;
1468:                boolean changes = false;
1469:                StringBuilder changesDesc = new StringBuilder(200);
1470:                FxProperty org = CacheAdmin.getEnvironment().getProperty(
1471:                        prop.getId());
1472:
1473:                try {
1474:                    if (con == null)
1475:                        con = Database.getDbConnection();
1476:                    sql.setLength(0);
1477:
1478:                    if (!org.isSystemInternal()
1479:                            || FxContext.get().getTicket().isGlobalSupervisor()) {
1480:
1481:                        if (org.mayOverrideBaseMultiplicity() != prop
1482:                                .mayOverrideBaseMultiplicity()) {
1483:                            if (!prop.mayOverrideBaseMultiplicity()) {
1484:                                if (getInstanceMultiplicity(con, org.getId(),
1485:                                        true) < prop.getMultiplicity().getMin())
1486:                                    throw new FxUpdateException(
1487:                                            "ex.structure.modification.contentExists",
1488:                                            "minimumMultiplicity");
1489:                                if (getInstanceMultiplicity(con, org.getId(),
1490:                                        false) > prop.getMultiplicity()
1491:                                        .getMax())
1492:                                    throw new FxUpdateException(
1493:                                            "ex.structure.modification.contentExists",
1494:                                            "maximumMultiplicity");
1495:                            }
1496:                            if (ps != null)
1497:                                ps.close();
1498:                            ps = con.prepareStatement("UPDATE "
1499:                                    + TBL_STRUCT_PROPERTIES
1500:                                    + " SET MAYOVERRIDEMULT=? WHERE ID=?");
1501:                            ps
1502:                                    .setBoolean(1, prop
1503:                                            .mayOverrideBaseMultiplicity());
1504:                            ps.setLong(2, prop.getId());
1505:                            ps.executeUpdate();
1506:                            if (changes)
1507:                                changesDesc.append(',');
1508:                            changesDesc.append("mayOverrideMultiplicity=")
1509:                                    .append(prop.mayOverrideBaseMultiplicity());
1510:                            changes = true;
1511:                        }
1512:
1513:                        if (org.getMultiplicity().getMin() != prop
1514:                                .getMultiplicity().getMin()
1515:                                || org.getMultiplicity().getMax() != prop
1516:                                        .getMultiplicity().getMax()) {
1517:                            if (!prop.mayOverrideBaseMultiplicity()) {
1518:                                if (org.getMultiplicity().getMin() < prop
1519:                                        .getMultiplicity().getMin()) {
1520:                                    if (getInstanceMultiplicity(con, org
1521:                                            .getId(), true) < prop
1522:                                            .getMultiplicity().getMin())
1523:                                        throw new FxUpdateException(
1524:                                                "ex.structure.modification.contentExists",
1525:                                                "minimumMultiplicity");
1526:                                }
1527:                                if (org.getMultiplicity().getMax() > prop
1528:                                        .getMultiplicity().getMax()) {
1529:                                    if (getInstanceMultiplicity(con, org
1530:                                            .getId(), false) > prop
1531:                                            .getMultiplicity().getMax())
1532:                                        throw new FxUpdateException(
1533:                                                "ex.structure.modification.contentExists",
1534:                                                "maximumMultiplicity");
1535:                                }
1536:                            }
1537:                            if (ps != null)
1538:                                ps.close();
1539:                            ps = con
1540:                                    .prepareStatement("UPDATE "
1541:                                            + TBL_STRUCT_PROPERTIES
1542:                                            + " SET DEFMINMULT=? ,DEFMAXMULT=? WHERE ID=?");
1543:                            ps.setInt(1, prop.getMultiplicity().getMin());
1544:                            ps.setInt(2, prop.getMultiplicity().getMax());
1545:                            ps.setLong(3, prop.getId());
1546:                            ps.executeUpdate();
1547:                            if (changes)
1548:                                changesDesc.append(',');
1549:                            changesDesc.append("multiplicity=").append(
1550:                                    prop.getMultiplicity());
1551:                            changes = true;
1552:                        }
1553:                        //not supported yet
1554:                        if (!org.getName().equals(prop.getName())) {
1555:                            throw new FxUpdateException(
1556:                                    "ex.structure.modification.notSuppoerted",
1557:                                    "name");
1558:                            /*
1559:                            if (ps != null) ps.close();
1560:                            ps = con.prepareStatement("UPDATE " + TBL_STRUCT_PROPERTIES + " SET NAME=? WHERE ID=?");
1561:                            ps.setString(1, prop.getName());
1562:                            ps.setLong(2, prop.getId());
1563:                            ps.executeUpdate();
1564:                            if (changes)
1565:                                changesDesc.append(',');
1566:                            changesDesc.append("name=").append(prop.getName());
1567:                            changes = true;
1568:                             */
1569:                        }
1570:                        //may only change if there are no existing content instances that use this property already
1571:                        if (org.getDataType().getId() != prop.getDataType()
1572:                                .getId()) {
1573:                            if (getPropertyInstanceCount(org.getId()) == 0) {
1574:                                if (ps != null)
1575:                                    ps.close();
1576:                                ps = con.prepareStatement("UPDATE "
1577:                                        + TBL_STRUCT_PROPERTIES
1578:                                        + " SET DATATYPE=? WHERE ID=?");
1579:                                ps.setLong(1, prop.getDataType().getId());
1580:                                ps.setLong(2, prop.getId());
1581:                                ps.executeUpdate();
1582:                                if (changes)
1583:                                    changesDesc.append(',');
1584:                                changesDesc.append("dataType=").append(
1585:                                        prop.getDataType().getName());
1586:                                changes = true;
1587:                            } else
1588:                                throw new FxUpdateException(
1589:                                        "ex.structure.modification.contentExists",
1590:                                        "dataType");
1591:                        }
1592:
1593:                        //may only change if there are no existing content instances that use this property already
1594:                        if (org.getReferencedType() != null
1595:                                && prop.getReferencedType() != null
1596:                                && org.getReferencedType().getId() != prop
1597:                                        .getReferencedType().getId()
1598:                                || org.hasReferencedType() != prop
1599:                                        .hasReferencedType()) {
1600:                            if (getPropertyInstanceCount(org.getId()) == 0) {
1601:                                ps = con.prepareStatement("UPDATE "
1602:                                        + TBL_STRUCT_PROPERTIES
1603:                                        + " SET REFTYPE=? WHERE ID=?");
1604:                                ps.setLong(2, prop.getId());
1605:                                if (prop.hasReferencedType()) {
1606:                                    ps.setLong(1, prop.getReferencedType()
1607:                                            .getId());
1608:                                } else
1609:                                    ps.setNull(1, java.sql.Types.NUMERIC);
1610:                                ps.executeUpdate();
1611:                                if (changes)
1612:                                    changesDesc.append(',');
1613:                                changesDesc.append("referencedType=").append(
1614:                                        prop.getReferencedType());
1615:                                changes = true;
1616:                            } else
1617:                                throw new FxUpdateException(
1618:                                        "ex.structure.modification.contentExists",
1619:                                        "referencedType");
1620:                        }
1621:
1622:                        if (org.isFulltextIndexed() != prop.isFulltextIndexed()) {
1623:                            if (ps != null)
1624:                                ps.close();
1625:                            ps = con.prepareStatement("UPDATE "
1626:                                    + TBL_STRUCT_PROPERTIES
1627:                                    + " SET ISFULLTEXTINDEXED=? WHERE ID=?");
1628:                            ps.setBoolean(1, prop.isFulltextIndexed());
1629:                            ps.setLong(2, prop.getId());
1630:                            ps.executeUpdate();
1631:                            if (changes)
1632:                                changesDesc.append(',');
1633:                            changesDesc.append("isFulltextIndexed=").append(
1634:                                    prop.isFulltextIndexed());
1635:                            changes = true;
1636:                        }
1637:                        if (org.mayOverrideACL() != prop.mayOverrideACL()) {
1638:                            if (ps != null)
1639:                                ps.close();
1640:                            ps = con.prepareStatement("UPDATE "
1641:                                    + TBL_STRUCT_PROPERTIES
1642:                                    + " SET MAYOVERRIDEACL=? WHERE ID=?");
1643:                            ps.setBoolean(1, prop.mayOverrideACL());
1644:                            ps.setLong(2, prop.getId());
1645:                            ps.executeUpdate();
1646:                            if (changes)
1647:                                changesDesc.append(',');
1648:                            changesDesc.append("mayOverrideACL=").append(
1649:                                    prop.mayOverrideACL());
1650:                            changes = true;
1651:                        }
1652:                        //may only change if there are no existing content instances that use this property already
1653:                        if (org.getReferencedList() != null
1654:                                && prop.getReferencedList() != null
1655:                                && org.getReferencedList().getId() != prop
1656:                                        .getReferencedList().getId()
1657:                                || org.hasReferencedList() != prop
1658:                                        .hasReferencedList()) {
1659:                            if (getPropertyInstanceCount(org.getId()) == 0) {
1660:                                ps = con.prepareStatement("UPDATE "
1661:                                        + TBL_STRUCT_PROPERTIES
1662:                                        + " SET REFLIST=? WHERE ID=?");
1663:                                ps.setLong(2, prop.getId());
1664:                                if (prop.hasReferencedList()) {
1665:                                    ps.setLong(1, prop.getReferencedList()
1666:                                            .getId());
1667:                                } else
1668:                                    ps.setNull(1, java.sql.Types.NUMERIC);
1669:                                ps.executeUpdate();
1670:                                if (changes)
1671:                                    changesDesc.append(',');
1672:                                changesDesc.append("referencedList=").append(
1673:                                        prop.getReferencedList());
1674:                                changes = true;
1675:                            } else
1676:                                throw new FxUpdateException(
1677:                                        "ex.structure.modification.contentExists",
1678:                                        "referencedList");
1679:                        }
1680:
1681:                        if (org.getUniqueMode() != prop.getUniqueMode()) {
1682:                            boolean allowChange = getPropertyInstanceCount(org
1683:                                    .getId()) == 0
1684:                                    || prop.getUniqueMode().equals(
1685:                                            UniqueMode.None);
1686:                            if (!allowChange) {
1687:                                boolean check = true;
1688:                                for (FxType type : CacheAdmin.getEnvironment()
1689:                                        .getTypesForProperty(prop.getId())) {
1690:                                    check = StorageManager.getContentStorage(
1691:                                            TypeStorageMode.Hierarchical)
1692:                                            .uniqueConditionValid(con,
1693:                                                    prop.getUniqueMode(), prop,
1694:                                                    type.getId(), null);
1695:                                    if (!check)
1696:                                        break;
1697:                                }
1698:                                allowChange = check;
1699:                            }
1700:                            if (allowChange) {
1701:                                if (ps != null)
1702:                                    ps.close();
1703:                                ps = con.prepareStatement("UPDATE "
1704:                                        + TBL_STRUCT_PROPERTIES
1705:                                        + " SET UNIQUEMODE=? WHERE ID=?");
1706:                                ps.setLong(1, prop.getUniqueMode().getId());
1707:                                ps.setLong(2, prop.getId());
1708:                                ps.executeUpdate();
1709:                                if (changes)
1710:                                    changesDesc.append(',');
1711:                                changesDesc.append("uniqueMode=").append(
1712:                                        prop.getUniqueMode().getId());
1713:                                changes = true;
1714:                            } else
1715:                                throw new FxUpdateException(
1716:                                        "ex.structure.modification.contentExists",
1717:                                        "uniqueMode");
1718:                        }
1719:
1720:                        if (org.getACL().getId() != prop.getACL().getId()) {
1721:                            if (ps != null)
1722:                                ps.close();
1723:                            ps = con.prepareStatement("UPDATE "
1724:                                    + TBL_STRUCT_PROPERTIES
1725:                                    + " SET ACL=? WHERE ID=?");
1726:                            ps.setLong(1, prop.getACL().getId());
1727:                            ps.setLong(2, prop.getId());
1728:                            ps.executeUpdate();
1729:                            if (changes)
1730:                                changesDesc.append(',');
1731:                            changesDesc.append("acl=").append(
1732:                                    prop.getACL().getId());
1733:                            changes = true;
1734:                        }
1735:                        if (org.getLabel() != null
1736:                                && !org.getLabel().equals(prop.getLabel())
1737:                                || org.getLabel() == null
1738:                                && prop.getLabel() != null
1739:                                || org.getHint() != null
1740:                                && !org.getHint().equals(prop.getHint())
1741:                                || org.getHint() == null
1742:                                && prop.getHint() != null
1743:                                || org.getDefaultValue() != null
1744:                                && !org.getDefaultValue().equals(
1745:                                        prop.getDefaultValue())
1746:                                || org.getDefaultValue() == null
1747:                                && prop.getDefaultValue() != null) {
1748:                            Database.storeFxString(new FxString[] {
1749:                                    prop.getLabel(), prop.getHint(),
1750:                                    prop.getDefaultValue() }, con,
1751:                                    TBL_STRUCT_PROPERTIES, new String[] {
1752:                                            "DESCRIPTION", "HINT",
1753:                                            "DEFAULT_VALUE" }, "ID", prop
1754:                                            .getId());
1755:                            if (changes)
1756:                                changesDesc.append(',');
1757:                            changesDesc.append("label=")
1758:                                    .append(prop.getLabel()).append(',');
1759:                            changesDesc.append("hint=").append(prop.getHint())
1760:                                    .append(',');
1761:                            changesDesc.append("defaultValue=").append(
1762:                                    prop.getDefaultValue());
1763:                            changes = true;
1764:                        }
1765:
1766:                        //update SystemInternal flag, this is a one way function, so it can only be set, but not reset!!
1767:                        if (!org.isSystemInternal() && prop.isSystemInternal()) {
1768:                            if (FxContext.get().getTicket()
1769:                                    .isGlobalSupervisor()) {
1770:                                if (ps != null)
1771:                                    ps.close();
1772:                                ps = con.prepareStatement("UPDATE "
1773:                                        + TBL_STRUCT_PROPERTIES
1774:                                        + " SET SYSINTERNAL=? WHERE ID=?");
1775:                                ps.setBoolean(1, prop.isSystemInternal());
1776:                                ps.setLong(2, prop.getId());
1777:                                ps.executeUpdate();
1778:                                if (changes)
1779:                                    changesDesc.append(',');
1780:                                changesDesc.append("systemInternal=").append(
1781:                                        prop.isSystemInternal());
1782:                                changes = true;
1783:                            } else
1784:                                throw new FxUpdateException(
1785:                                        "ex.structure.modification.systemInternal.notGlobalSupervisor",
1786:                                        prop.getName());
1787:                        }
1788:                    }
1789:                    if (updatePropertyOptions(con, prop)) {
1790:                        changesDesc.append(",options:");
1791:                        List<FxStructureOption> options = prop.getOptions();
1792:                        for (FxStructureOption option : options) {
1793:                            changesDesc.append(option.getKey()).append("=")
1794:                                    .append(option.getValue()).append(
1795:                                            " overridable=").append(
1796:                                            option.isOverrideable()).append(
1797:                                            " isSet=").append(option.isSet());
1798:                        }
1799:                        changes = true;
1800:                    }
1801:
1802:                    if (changes) {
1803:                        //TODO: invoke htracker with changeDesc
1804:                    }
1805:                } catch (SQLException e) {
1806:                    ctx.setRollbackOnly();
1807:                    /*TODO: Determine if this must be checked
1808:                    if (Database.isUniqueConstraintViolation(e))
1809:                        throw new FxEntryExistsException("ex.structure.assignment.property.exists", prop.getAlias(), prop.getXPath());
1810:                     */
1811:                    throw new FxCreateException(LOG, e, "ex.db.sqlError", e
1812:                            .getMessage());
1813:                } finally {
1814:                    if (_con == null) {
1815:                        Database.closeObjects(AssignmentEngineBean.class, con,
1816:                                ps);
1817:                    }
1818:                }
1819:                return changes;
1820:            }
1821:
1822:            /**
1823:             * @param _con     database conneciton
1824:             * @param ps       prepared statement
1825:             * @param sql      StringBuilder to cache query creation
1826:             * @param original the original property assignment to compare changes
1827:             *                 against and update. if==null, the original will be fetched from the cache
1828:             * @param modified the modified property assignment
1829:             * @return if any changes were found
1830:             * @throws FxApplicationException on errors
1831:             */
1832:
1833:            private boolean updatePropertyAssignment(Connection _con,
1834:                    PreparedStatement ps, StringBuilder sql,
1835:                    FxPropertyAssignment original,
1836:                    FxPropertyAssignmentEdit modified)
1837:                    throws FxApplicationException {
1838:                if (sql == null)
1839:                    sql = new StringBuilder(1000);
1840:                if (modified.isNew())
1841:                    throw new FxInvalidParameterException(
1842:                            "ex.structure.assignment.update.new", modified
1843:                                    .getXPath());
1844:                Connection con = _con;
1845:                boolean changes = false;
1846:                StringBuilder changesDesc = new StringBuilder(200);
1847:                if (original == null)
1848:                    original = (FxPropertyAssignment) CacheAdmin
1849:                            .getEnvironment().getAssignment(modified.getId());
1850:                try {
1851:                    if (con == null)
1852:                        con = Database.getDbConnection();
1853:                    sql.setLength(0);
1854:
1855:                    if (!original.isSystemInternal()
1856:                            || FxContext.get().getTicket().isGlobalSupervisor()) {
1857:                        if (original.isEnabled() != modified.isEnabled()) {
1858:                            if (!modified.isEnabled())
1859:                                removeAssignment(original.getId(), true, false,
1860:                                        true);
1861:                            else {
1862:                                if (ps != null)
1863:                                    ps.close();
1864:                                ps = con.prepareStatement("UPDATE "
1865:                                        + TBL_STRUCT_ASSIGNMENTS
1866:                                        + " SET ENABLED=? WHERE ID=?");
1867:                                ps.setBoolean(1, modified.isEnabled());
1868:                                ps.setLong(2, original.getId());
1869:                                ps.executeUpdate();
1870:                            }
1871:                            if (changes)
1872:                                changesDesc.append(',');
1873:                            changesDesc.append("enabled=").append(
1874:                                    modified.isEnabled());
1875:                            changes = true;
1876:                        }
1877:                        if (original.getDefaultMultiplicity() != modified
1878:                                .getDefaultMultiplicity()) {
1879:                            if (ps != null)
1880:                                ps.close();
1881:                            ps = con.prepareStatement("UPDATE "
1882:                                    + TBL_STRUCT_ASSIGNMENTS
1883:                                    + " SET DEFMULT=? WHERE ID=?");
1884:                            ps.setInt(1, modified.getDefaultMultiplicity());
1885:                            ps.setLong(2, original.getId());
1886:                            ps.executeUpdate();
1887:                            if (changes)
1888:                                changesDesc.append(',');
1889:                            changesDesc.append("defaultMultiplicity=").append(
1890:                                    modified.getDefaultMultiplicity());
1891:                            changes = true;
1892:                        }
1893:
1894:                        //must not change
1895:                        /*
1896:                        if (org.getAssignedType().getId() != prop.getAssignedType().getId()) {
1897:                            if (ps != null) ps.close();
1898:                            ps = con.prepareStatement("UPDATE " + TBL_STRUCT_ASSIGNMENTS + " SET TYPEDEF=? WHERE ID=?");
1899:                            ps.setLong(1, prop.getAssignedType().getId());
1900:                            ps.setLong(2, prop.getId());
1901:                            ps.executeUpdate();
1902:                            if (changes)
1903:                                changesDesc.append(',');
1904:                            changesDesc.append("assignedType=").append(prop.getAssignedType());
1905:                            changes = true;
1906:                        }
1907:                         */
1908:
1909:                        if (original.getMultiplicity().getMin() != modified
1910:                                .getMultiplicity().getMin()
1911:                                || original.getMultiplicity().getMax() != modified
1912:                                        .getMultiplicity().getMax()) {
1913:                            if (modified.getProperty()
1914:                                    .mayOverrideBaseMultiplicity()) {
1915:                                if (getInstanceMultiplicity(con, modified
1916:                                        .getProperty().getId(), true) < modified
1917:                                        .getMultiplicity().getMin())
1918:                                    throw new FxUpdateException(
1919:                                            "ex.structure.modification.contentExists",
1920:                                            "minimumMultiplicity");
1921:                                if (getInstanceMultiplicity(con, modified
1922:                                        .getProperty().getId(), false) > modified
1923:                                        .getMultiplicity().getMax())
1924:                                    throw new FxUpdateException(
1925:                                            "ex.structure.modification.contentExists",
1926:                                            "maximumMultiplicity");
1927:                            }
1928:                            if (ps != null)
1929:                                ps.close();
1930:                            ps = con.prepareStatement("UPDATE "
1931:                                    + TBL_STRUCT_ASSIGNMENTS
1932:                                    + " SET MINMULT=? ,MAXMULT=? WHERE ID=?");
1933:                            ps.setInt(1, modified.getMultiplicity().getMin());
1934:                            ps.setInt(2, modified.getMultiplicity().getMax());
1935:                            ps.setLong(3, original.getId());
1936:                            ps.executeUpdate();
1937:                            if (changes)
1938:                                changesDesc.append(',');
1939:                            changesDesc.append("multiplicity=").append(
1940:                                    modified.getMultiplicity());
1941:                            changes = true;
1942:                        }
1943:                        if (original.getPosition() != modified.getPosition()) {
1944:                            int finalPos = setAssignmentPosition(con, modified
1945:                                    .getId(), modified.getPosition());
1946:                            if (changes)
1947:                                changesDesc.append(',');
1948:                            changesDesc.append("position=").append(finalPos);
1949:                            changes = true;
1950:                        }
1951:                        //not supported yet
1952:                        if (!original.getXPath().equals(modified.getXPath())) {
1953:                            throw new FxUpdateException(
1954:                                    "ex.structure.modification.notSuppoerted",
1955:                                    "xPath");
1956:                            /*
1957:                            //TODO:check for valid XPath
1958:                            if (ps != null) ps.close();
1959:                            ps = con.prepareStatement("UPDATE " + TBL_STRUCT_ASSIGNMENTS + " SET XPATH=? WHERE ID=?");
1960:                            ps.setString(1, prop.getXPath());
1961:                            ps.setLong(2, prop.getId());
1962:                            ps.executeUpdate();
1963:                            if (changes)
1964:                                changesDesc.append(',');
1965:                            changesDesc.append("xPath=").append(prop.getXPath());
1966:                            changes = true;
1967:                             */
1968:                        }
1969:                        //not supported yet
1970:                        if (!original.getAlias().equals(modified.getAlias())) {
1971:                            throw new FxUpdateException(
1972:                                    "ex.structure.modification.notSuppoerted",
1973:                                    "alias");
1974:                            /*
1975:                            if (ps != null) ps.close();
1976:                            ps = con.prepareStatement("UPDATE " + TBL_STRUCT_ASSIGNMENTS + " SET XALIAS=? WHERE ID=?");
1977:                            ps.setString(1, prop.getAlias());
1978:                            ps.setLong(2, prop.getId());
1979:                            ps.executeUpdate();
1980:                            if (changes)
1981:                                changesDesc.append(',');
1982:                            changesDesc.append("alias=").append(prop.getAlias());
1983:                            changes = true;
1984:                             */
1985:                        }
1986:                        //must not change
1987:                        /*
1988:                        if (org.getBaseAssignmentId() != prop.getBaseAssignmentId()) {
1989:                            if (ps != null) ps.close();
1990:                            ps = con.prepareStatement("UPDATE " + TBL_STRUCT_ASSIGNMENTS + " SET BASE=? WHERE ID=?");
1991:                            ps.setLong(1, prop.getBaseAssignmentId());
1992:                            ps.setLong(2, prop.getId());
1993:                            ps.executeUpdate();
1994:                            if (changes)
1995:                                changesDesc.append(',');
1996:                            changesDesc.append("baseAssignment=").append(prop.getBaseAssignmentId());
1997:                            changes = true;
1998:                        }
1999:                         */
2000:                        //must not change
2001:                        /*
2002:                        if(org.getParentGroupAssignment() != null &&
2003:                                !org.getParentGroupAssignment().equals(prop.getParentGroupAssignment()) ||
2004:                                prop.getParentGroupAssignment() !=null &&
2005:                                !prop.getParentGroupAssignment().equals(org.getParentGroupAssignment())) {
2006:                            if (ps != null) ps.close();
2007:                            ps = con.prepareStatement("UPDATE " + TBL_STRUCT_ASSIGNMENTS + " SET PARENTGROUP=? WHERE ID=?");
2008:                            if (prop.getParentGroupAssignment() !=null)
2009:                                ps.setLong(1, prop.getParentGroupAssignment().getId());
2010:                            else
2011:                                ps.setLong(1, FxAssignment.NO_PARENT);
2012:                            ps.setLong(2, prop.getId());
2013:                            ps.executeUpdate();
2014:                            if (changes)
2015:                                changesDesc.append(',');
2016:                            changesDesc.append("parentGroupAssignment=").append(prop.getParentGroupAssignment());
2017:                            changes = true;
2018:                        }
2019:                         */
2020:                        //must not change
2021:                        /*
2022:                        if(org.getProperty().getId() != prop.getProperty().getId()) {
2023:                            if (ps != null) ps.close();
2024:                            ps = con.prepareStatement("UPDATE " + TBL_STRUCT_ASSIGNMENTS + " SET APROPERTY=? WHERE ID=?");
2025:                            ps.setLong(1, prop.getProperty().getId());
2026:                            ps.setLong(2, prop.getId());
2027:                            ps.executeUpdate();
2028:                            if (changes)
2029:                                changesDesc.append(',');
2030:                            changesDesc.append("property=").append(prop.getProperty().getId());
2031:                            changes = true;
2032:                        }
2033:                         */
2034:                        if (original.getACL().getId() != modified.getACL()
2035:                                .getId()) {
2036:                            if (ps != null)
2037:                                ps.close();
2038:                            ps = con.prepareStatement("UPDATE "
2039:                                    + TBL_STRUCT_ASSIGNMENTS
2040:                                    + " SET ACL=? WHERE ID=?");
2041:                            ps.setLong(1, modified.getACL().getId());
2042:                            ps.setLong(2, original.getId());
2043:                            ps.executeUpdate();
2044:                            if (changes)
2045:                                changesDesc.append(',');
2046:                            changesDesc.append("acl=").append(
2047:                                    modified.getACL().getId());
2048:                            changes = true;
2049:                        }
2050:
2051:                        /* options are stored via storeOption method
2052:                        if (org.isMultiLang() != prop.isMultiLang()) {
2053:                            //TODO: only allow changes from multi to single lingual if no contents exist or all are of the same language
2054:                            //Multi->Single: lang=system
2055:                            //Single->Multi: lang=default language
2056:                            if( !org.getProperty().mayOverrideMultiLang() )
2057:                                throw new FxUpdateException("ex.structure.assignment.overrideNotAllowed.multiLang", org.getXPath(),
2058:                                        org.getProperty().getName()).setAffectedXPath(org.getXPath());
2059:                            if (ps != null) ps.close();
2060:                            ps = con.prepareStatement("UPDATE " + TBL_STRUCT_ASSIGNMENTS + " SET ISMULTILANG=? WHERE ID=?");
2061:                            ps.setBoolean(1, prop.isMultiLang());
2062:                            ps.setLong(2, prop.getId());
2063:                            ps.executeUpdate();
2064:                            if (changes)
2065:                                changesDesc.append(',');
2066:                            changesDesc.append("multiLang=").append(prop.isMultiLang());
2067:                            changes = true;
2068:                        }
2069:                         */
2070:                        if (original.getLabel() != null
2071:                                && !original.getLabel().equals(
2072:                                        modified.getLabel())
2073:                                || original.getLabel() == null
2074:                                && modified.getLabel() != null
2075:                                || original.getHint() != null
2076:                                && !original.getHint().equals(
2077:                                        modified.getHint())
2078:                                || original.getHint() == null
2079:                                && modified.getHint() != null
2080:                                || original.getDefaultValue() != null
2081:                                && !original.getDefaultValue().equals(
2082:                                        modified.getDefaultValue())
2083:                                || original.getDefaultValue() == null
2084:                                && modified.getDefaultValue() != null) {
2085:                            Database.storeFxString(new FxString[] {
2086:                                    modified.getLabel(), modified.getHint(),
2087:                                    (FxString) modified.getDefaultValue() },
2088:                                    con, TBL_STRUCT_ASSIGNMENTS, new String[] {
2089:                                            "DESCRIPTION", "HINT",
2090:                                            "DEFAULT_VALUE" }, "ID", original
2091:                                            .getId());
2092:                            if (changes)
2093:                                changesDesc.append(',');
2094:                            changesDesc.append("label=").append(
2095:                                    modified.getLabel()).append(',');
2096:                            changesDesc.append("hint=").append(
2097:                                    modified.getHint()).append(',');
2098:                            changesDesc.append("defaultValue=").append(
2099:                                    modified.getDefaultValue());
2100:                            changes = true;
2101:                        }
2102:                        if (original.getDefaultLanguage() != modified
2103:                                .getDefaultLanguage()) {
2104:                            if (ps != null)
2105:                                ps.close();
2106:                            ps = con.prepareStatement("UPDATE "
2107:                                    + TBL_STRUCT_ASSIGNMENTS
2108:                                    + " SET DEFLANG=? WHERE ID=?");
2109:                            ps.setInt(1, (int) modified.getDefaultLanguage());
2110:                            ps.setLong(2, original.getId());
2111:                            ps.executeUpdate();
2112:                            if (changes)
2113:                                changesDesc.append(',');
2114:                            changesDesc.append("defaultLanguage=").append(
2115:                                    modified.getDefaultLanguage());
2116:                            changes = true;
2117:                        }
2118:
2119:                        if (original.getDefaultMultiplicity() != modified
2120:                                .getDefaultMultiplicity()) {
2121:                            if (modified.getMultiplicity().getMin() > modified
2122:                                    .getDefaultMultiplicity()
2123:                                    || modified.getDefaultMultiplicity() > modified
2124:                                            .getMultiplicity().getMax())
2125:                                throw new FxUpdateException(
2126:                                        "ex.structure.modificaiton.defaultMultiplicity.invalid");
2127:
2128:                            if (ps != null)
2129:                                ps.close();
2130:                            ps = con.prepareStatement("UPDATE "
2131:                                    + TBL_STRUCT_ASSIGNMENTS
2132:                                    + " SET DEFMULT=? WHERE ID=?");
2133:                            ps.setInt(1, modified.getDefaultMultiplicity());
2134:                            ps.setLong(2, original.getId());
2135:                            ps.executeUpdate();
2136:                            if (changes)
2137:                                changesDesc.append(',');
2138:                            changesDesc.append("defaultMultiplicity=").append(
2139:                                    modified.getDefaultMultiplicity());
2140:                            changes = true;
2141:                        }
2142:                        //update SystemInternal flag, this is a one way function, so it can only be set, but not reset!!
2143:                        if (!original.isSystemInternal()
2144:                                && modified.isSystemInternal()) {
2145:                            if (FxContext.get().getTicket()
2146:                                    .isGlobalSupervisor()) {
2147:                                if (ps != null)
2148:                                    ps.close();
2149:                                ps = con.prepareStatement("UPDATE "
2150:                                        + TBL_STRUCT_ASSIGNMENTS
2151:                                        + " SET SYSINTERNAL=? WHERE ID=?");
2152:                                ps.setBoolean(1, modified.isSystemInternal());
2153:                                ps.setLong(2, original.getId());
2154:                                ps.executeUpdate();
2155:                                if (changes)
2156:                                    changesDesc.append(',');
2157:                                changesDesc.append("systemInternal=").append(
2158:                                        modified.isSystemInternal());
2159:                                changes = true;
2160:                            } else
2161:                                throw new FxUpdateException(
2162:                                        "ex.structure.modification.systemInternal.notGlobalSupervisor",
2163:                                        modified.getLabel());
2164:                        }
2165:                        /*
2166:                        if (changes) {
2167:                            //propagate changes to derived assignments
2168:                            List<FxAssignment> children = CacheAdmin.getEnvironment().getDerivedAssignments(modified.getId());
2169:                            for (FxAssignment as : children) {
2170:                                if (as instanceof FxPropertyAssignment) {
2171:                                    updatePropertyAssignment(null, null, null, (FxPropertyAssignment) as, modified);
2172:                                }
2173:                            }
2174:                            //if there are changes AND the assignment is a child,
2175:                            // break the inheritance and make it a "ROOT_BASE" assignment
2176:                            if(original.isDerivedAssignment()) {
2177:                                if (ps!=null)
2178:                                    ps.close();
2179:                                ps = con.prepareStatement("UPDATE " + TBL_STRUCT_ASSIGNMENTS + " SET BASE=? WHERE ID=?");
2180:                                ps.setNull(1, Types.NUMERIC);
2181:                                ps.setLong(2, original.getId());
2182:                                ps.executeUpdate();
2183:                                   changesDesc.append(",baseAssignment=null");
2184:                            }
2185:                        }
2186:                         */
2187:                    } else
2188:                        throw new FxUpdateException(
2189:                                "ex.structure.systemInternal.forbidden",
2190:                                modified.getLabel());
2191:
2192:                    if (updatePropertyAssignmentOptions(con, original, modified)) {
2193:                        changesDesc.append(",options:");
2194:                        List<FxStructureOption> options = modified.getOptions();
2195:                        for (FxStructureOption option : options) {
2196:                            changesDesc.append(option.getKey()).append("=")
2197:                                    .append(option.getValue()).append(
2198:                                            " overridable=").append(
2199:                                            option.isOverrideable()).append(
2200:                                            " isSet=").append(option.isSet());
2201:                        }
2202:                        changes = true;
2203:                    }
2204:
2205:                    //TODO: compare all possible modifications
2206:                    if (changes)
2207:                        htracker.track(modified.getAssignedType(),
2208:                                "history.assignment.updatePropertyAssignment",
2209:                                original.getXPath(), modified.getAssignedType()
2210:                                        .getId(), modified.getAssignedType()
2211:                                        .getName(), modified.getProperty()
2212:                                        .getId(), modified.getProperty()
2213:                                        .getName(), changesDesc.toString());
2214:                } catch (SQLException e) {
2215:                    final boolean uniqueConstraintViolation = Database
2216:                            .isUniqueConstraintViolation(e);
2217:                    ctx.setRollbackOnly();
2218:                    if (uniqueConstraintViolation)
2219:                        throw new FxEntryExistsException(
2220:                                "ex.structure.assignment.property.exists",
2221:                                original.getAlias(), original.getXPath());
2222:                    throw new FxCreateException(LOG, e, "ex.db.sqlError", e
2223:                            .getMessage());
2224:                } finally {
2225:                    if (_con == null) {
2226:                        Database.closeObjects(AssignmentEngineBean.class, con,
2227:                                ps);
2228:                    }
2229:                }
2230:                return changes;
2231:            }
2232:
2233:            private long createPropertyAssignment(Connection _con,
2234:                    PreparedStatement ps, StringBuilder sql,
2235:                    FxPropertyAssignmentEdit prop)
2236:                    throws FxApplicationException {
2237:                if (sql == null)
2238:                    sql = new StringBuilder(1000);
2239:                if (!prop.isNew())
2240:                    throw new FxInvalidParameterException(
2241:                            "ex.structure.assignment.create.existing", prop
2242:                                    .getXPath());
2243:                Connection con = _con;
2244:                long newAssignmentId;
2245:                try {
2246:                    if (con == null)
2247:                        con = Database.getDbConnection();
2248:                    sql.setLength(0);
2249:                    sql.append("INSERT INTO ")
2250:                            .append(TBL_STRUCT_ASSIGNMENTS)
2251:                            .
2252:                            //               1  2     3       4       5       6       7       8   9     10     11   12          13
2253:                            append(
2254:                                    "(ID,ATYPE,ENABLED,TYPEDEF,MINMULT,MAXMULT,DEFMULT,POS,XPATH,XALIAS,BASE,PARENTGROUP,APROPERTY,"
2255:                                            +
2256:                                            //14 15      16
2257:                                            "ACL,DEFLANG,SYSINTERNAL)"
2258:                                            + "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
2259:                    if (ps != null)
2260:                        ps.close();
2261:                    ps = con.prepareStatement(sql.toString());
2262:                    newAssignmentId = seq
2263:                            .getId(SequencerEngine.System.ASSIGNMENT);
2264:                    ps.setLong(1, newAssignmentId);
2265:                    ps.setInt(2, FxAssignment.TYPE_PROPERTY);
2266:                    ps.setBoolean(3, prop.isEnabled());
2267:                    ps.setLong(4, prop.getAssignedType().getId());
2268:                    ps.setInt(5, prop.getMultiplicity().getMin());
2269:                    ps.setInt(6, prop.getMultiplicity().getMax());
2270:                    ps.setInt(7, prop.getDefaultMultiplicity());
2271:                    int position = getValidPosition(con, sql, prop
2272:                            .getPosition(), prop.getAssignedType().getId(),
2273:                            prop.getParentGroupAssignment());
2274:                    ps.setInt(8, position);
2275:                    String XPath;
2276:                    if (!prop.getXPath().startsWith(
2277:                            prop.getAssignedType().getName()))
2278:                        XPath = XPathElement.buildXPath(false, prop
2279:                                .getAssignedType().getName(), prop.getXPath());
2280:                    else
2281:                        XPath = prop.getXPath();
2282:                    ps.setString(9, XPath);
2283:                    ps.setString(10, prop.getAlias());
2284:                    ps.setLong(11, prop.getBaseAssignmentId());
2285:                    ps
2286:                            .setLong(
2287:                                    12,
2288:                                    prop.getParentGroupAssignment() == null ? FxAssignment.NO_PARENT
2289:                                            : prop.getParentGroupAssignment()
2290:                                                    .getId());
2291:                    ps.setLong(13, prop.getProperty().getId());
2292:                    ps.setLong(14, prop.getACL().getId());
2293:                    ps.setInt(15, prop.hasDefaultLanguage() ? (int) prop
2294:                            .getDefaultLanguage() : (int) FxLanguage.SYSTEM_ID);
2295:                    ps.setBoolean(16, prop.isSystemInternal());
2296:                    ps.executeUpdate();
2297:                    Database.storeFxString(
2298:                            new FxString[] { prop.getLabel(), prop.getHint(),
2299:                                    (FxString) prop.getDefaultValue() }, con,
2300:                            TBL_STRUCT_ASSIGNMENTS, new String[] {
2301:                                    "DESCRIPTION", "HINT", "DEFAULT_VALUE" },
2302:                            "ID", newAssignmentId);
2303:                    htracker.track(prop.getAssignedType(),
2304:                            "history.assignment.createPropertyAssignment",
2305:                            XPath, prop.getAssignedType().getId(), prop
2306:                                    .getAssignedType().getName(), prop
2307:                                    .getProperty().getId(), prop.getProperty()
2308:                                    .getName());
2309:                    storeOptions(con, TBL_PROPERTY_OPTIONS, "ID", prop
2310:                            .getProperty().getId(), newAssignmentId, prop
2311:                            .getOptions());
2312:                    setAssignmentPosition(con, newAssignmentId, prop
2313:                            .getPosition());
2314:                    if (!prop.isSystemInternal()) {
2315:                        //only need a reload and inheritance handling if the property is not system internal
2316:                        //since system internal properties are only created from the type engine we don't have to care
2317:                        try {
2318:                            StructureLoader.reload(con);
2319:                        } catch (FxCacheException e) {
2320:                            ctx.setRollbackOnly();
2321:                            throw new FxCreateException(e, "ex.cache", e
2322:                                    .getMessage());
2323:                        }
2324:                        createInheritedAssignments(CacheAdmin.getEnvironment()
2325:                                .getAssignment(newAssignmentId), con, ps, sql,
2326:                                prop.getAssignedType().getDerivedTypes());
2327:                    }
2328:                } catch (SQLException e) {
2329:                    final boolean uniqueConstraintViolation = Database
2330:                            .isUniqueConstraintViolation(e);
2331:                    ctx.setRollbackOnly();
2332:                    if (uniqueConstraintViolation)
2333:                        throw new FxEntryExistsException(
2334:                                "ex.structure.assignment.property.exists", prop
2335:                                        .getAlias(), prop.getXPath());
2336:                    throw new FxCreateException(LOG, e, "ex.db.sqlError", e
2337:                            .getMessage());
2338:                } finally {
2339:                    Database.closeObjects(AssignmentEngineBean.class,
2340:                            (_con == null ? con : null), ps);
2341:                }
2342:                return newAssignmentId;
2343:            }
2344:
2345:            /**
2346:             * Get a valid position for the assignment within the same hierarchy.
2347:             * Probes for the desired position first and if taken returns the next available
2348:             *
2349:             * @param con                   connection ( has to be valid and open!)
2350:             * @param sql                   StringBuilder for the statement
2351:             * @param desiredPos            desired position
2352:             * @param typeId                FxType id
2353:             * @param parentGroupAssignment the parent gorup assignment or <code>null</code> if assigned to the root
2354:             * @return a valid position for the assignment
2355:             * @throws SQLException      on errors
2356:             * @throws FxCreateException if no result could be retrieved
2357:             */
2358:            private int getValidPosition(Connection con, StringBuilder sql,
2359:                    int desiredPos, long typeId,
2360:                    FxGroupAssignment parentGroupAssignment)
2361:                    throws SQLException, FxCreateException {
2362:                //      original MySQL statement:
2363:                //        select if( (select count(id) from FXS_ASSIGNMENTS where typedef=1 and parentgroup=0 and pos=1) > 0,
2364:                //             (select (max(pos)+1) from FXS_ASSIGNMENTS WHERE typedef=1 and parentgroup=0),
2365:                //             1) as pos
2366:                PreparedStatement ps = null;
2367:                sql.setLength(0);
2368:                sql
2369:                        .append("SELECT IF((SELECT COUNT(ID) FROM ")
2370:                        .append(TBL_STRUCT_ASSIGNMENTS)
2371:                        .
2372:                        //                             1                 2         3
2373:                        append(
2374:                                " WHERE TYPEDEF=? AND PARENTGROUP=? AND POS=?)>0,(SELECT IFNULL(MAX(POS)+1,0) FROM ")
2375:                        .
2376:                        //                                                            4                 5  6
2377:                        append(TBL_STRUCT_ASSIGNMENTS).append(
2378:                                " WHERE TYPEDEF=? AND PARENTGROUP=?),?)");
2379:                try {
2380:                    ps = con.prepareStatement(sql.toString());
2381:                    ps.setLong(1, typeId);
2382:                    ps
2383:                            .setLong(
2384:                                    2,
2385:                                    parentGroupAssignment == null ? FxAssignment.NO_PARENT
2386:                                            : parentGroupAssignment.getId());
2387:                    ps.setInt(3, desiredPos);
2388:                    ps.setLong(4, typeId);
2389:                    ps
2390:                            .setLong(
2391:                                    5,
2392:                                    parentGroupAssignment == null ? FxAssignment.NO_PARENT
2393:                                            : parentGroupAssignment.getId());
2394:                    ps.setInt(6, desiredPos);
2395:                    ResultSet rs = ps.executeQuery();
2396:                    if (rs != null && rs.next())
2397:                        return rs.getInt(1);
2398:                    throw new FxCreateException(
2399:                            "ex.structure.position.failed",
2400:                            typeId,
2401:                            parentGroupAssignment == null ? FxAssignment.NO_PARENT
2402:                                    : parentGroupAssignment.getId(), desiredPos);
2403:                } finally {
2404:                    if (ps != null)
2405:                        ps.close();
2406:                }
2407:            }
2408:
2409:            /**
2410:             * {@inheritDoc}
2411:             */
2412:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
2413:            public void removeAssignment(long assignmentId,
2414:                    boolean removeSubAssignments,
2415:                    boolean removeDerivedAssignments)
2416:                    throws FxApplicationException {
2417:                removeAssignment(assignmentId, removeSubAssignments,
2418:                        removeDerivedAssignments, false);
2419:            }
2420:
2421:            private void removeAssignment(long assignmentId,
2422:                    boolean removeSubAssignments,
2423:                    boolean removeDerivedAssignments, boolean disableAssignment)
2424:                    throws FxApplicationException {
2425:                final UserTicket ticket = FxContext.get().getTicket();
2426:                FxPermissionUtils.checkRole(ticket, Role.StructureManagement);
2427:                FxAssignment assignment;
2428:                assignment = CacheAdmin.getEnvironment().getAssignment(
2429:                        assignmentId);
2430:                assert assignment != null : "Assignment retrieved was null";
2431:                if (!disableAssignment) {
2432:                    //if removal, check if its a derived assignment which may not be removed
2433:                    if (assignment.isDerivedAssignment())
2434:                        throw new FxRemoveException(
2435:                                "ex.structure.assignment.delete.derived",
2436:                                assignment.getXPath());
2437:                }
2438:
2439:                Connection con = null;
2440:                PreparedStatement ps = null;
2441:                StringBuilder sql = new StringBuilder(500);
2442:                try {
2443:                    con = Database.getDbConnection();
2444:
2445:                    List<FxAssignment> affectedAssignments = new ArrayList<FxAssignment>(
2446:                            10);
2447:                    affectedAssignments.add(assignment);
2448:
2449:                    if (assignment instanceof  FxGroupAssignment
2450:                            && removeSubAssignments) {
2451:                        FxGroupAssignment ga = (FxGroupAssignment) assignment;
2452:                        _addSubAssignments(affectedAssignments, ga);
2453:                    }
2454:
2455:                    if (removeDerivedAssignments) {
2456:                        //find all derived assignments
2457:                        sql.append("SELECT ID FROM ").append(
2458:                                TBL_STRUCT_ASSIGNMENTS).append(" WHERE BASE=?");
2459:                        ps = con.prepareStatement(sql.toString());
2460:                        long prevSize = 0;
2461:                        while (prevSize != affectedAssignments.size()) { //run until no derived assignments are found
2462:                            prevSize = affectedAssignments.size();
2463:                            List<FxAssignment> adds = new ArrayList<FxAssignment>(
2464:                                    5);
2465:                            for (FxAssignment check : affectedAssignments) {
2466:                                ps.setLong(1, check.getId());
2467:                                ResultSet rs = ps.executeQuery();
2468:                                if (rs != null && rs.next()) {
2469:                                    FxAssignment derived = CacheAdmin
2470:                                            .getEnvironment().getAssignment(
2471:                                                    rs.getLong(1));
2472:                                    if (!adds.contains(derived)
2473:                                            && !affectedAssignments
2474:                                                    .contains(derived))
2475:                                        adds.add(derived);
2476:                                }
2477:                            }
2478:                            affectedAssignments.addAll(adds);
2479:                        }
2480:                        ps.close();
2481:                        sql.setLength(0);
2482:                    } else if (!disableAssignment) {
2483:                        //find all (directly) derived assignments, flag them as 'regular' assignments and set them as new base
2484:                        ps = breakAssignmentInheritance(con, assignment, sql);
2485:                    }
2486:
2487:                    //security checks
2488:                    if (!ticket.isGlobalSupervisor()) {
2489:                        //assignment permission
2490:                        StringBuilder assignmentList = new StringBuilder(200);
2491:                        for (FxAssignment check : affectedAssignments) {
2492:                            assignmentList.append(",").append(check.getId());
2493:                            if (check instanceof  FxPropertyAssignment
2494:                                    && check.getAssignedType()
2495:                                            .usePropertyPermissions()) {
2496:                                FxPropertyAssignment pa = (FxPropertyAssignment) check;
2497:                                if (!ticket
2498:                                        .mayDeleteACL(pa.getACL().getId(), 0/*owner is irrelevant here*/))
2499:                                    throw new FxNoAccessException(
2500:                                            "ex.acl.noAccess.delete", pa
2501:                                                    .getACL().getName());
2502:                            }
2503:                        }
2504:                        //affected content permission
2505:                        sql.append("SELECT DISTINCT O.ACL FROM ").append(
2506:                                TBL_CONTENT).append(
2507:                                " O WHERE O.ID IN(SELECT D.ID FROM ").append(
2508:                                TBL_CONTENT_DATA).append(
2509:                                " D WHERE D.ASSIGN IN(").append(
2510:                                assignmentList.substring(1)).append("))");
2511:                        java.lang.System.out.println("SQL==" + sql.toString());
2512:                        ps = con.prepareStatement(sql.toString());
2513:                        sql.setLength(0);
2514:                        ResultSet rs = ps.executeQuery();
2515:                        while (rs != null && rs.next()) {
2516:                            if (!ticket
2517:                                    .mayDeleteACL(rs.getInt(1), 0/*owner is irrelevant here*/))
2518:                                throw new FxNoAccessException(
2519:                                        "ex.acl.noAccess.delete", CacheAdmin
2520:                                                .getEnvironment().getACL(
2521:                                                        rs.getInt(1)));
2522:                        }
2523:                        ps.close();
2524:                    }
2525:
2526:                    if (disableAssignment)
2527:                        sql.append("UPDATE ").append(TBL_STRUCT_ASSIGNMENTS)
2528:                                .append(" SET ENABLED=? WHERE ID=?");
2529:                    else
2530:                        sql.append("DELETE FROM ").append(
2531:                                TBL_STRUCT_ASSIGNMENTS).append(" WHERE ID=?");
2532:                    ps = con.prepareStatement(sql.toString());
2533:
2534:                    //batch remove all multi language entries and content datas
2535:                    PreparedStatement psML = null;
2536:                    PreparedStatement psData = null;
2537:                    PreparedStatement psDataFT = null;
2538:                    PreparedStatement psBinaryGet = null;
2539:                    PreparedStatement psBinaryRemove = null;
2540:                    PreparedStatement psPropertyOptionRemove;
2541:                    PreparedStatement psGroupOptionRemove;
2542:                    try {
2543:                        sql.setLength(0);
2544:                        sql.append("DELETE FROM ").append(
2545:                                TBL_STRUCT_ASSIGNMENTS).append(ML).append(
2546:                                " WHERE ID=?");
2547:                        psML = con.prepareStatement(sql.toString());
2548:                        sql.setLength(0);
2549:                        sql.append("DELETE FROM ").append(TBL_PROPERTY_OPTIONS)
2550:                                .append(" WHERE ASSID=?");
2551:                        psPropertyOptionRemove = con.prepareStatement(sql
2552:                                .toString());
2553:                        sql.setLength(0);
2554:                        sql.append("DELETE FROM ").append(TBL_GROUP_OPTIONS)
2555:                                .append(" WHERE ASSID=?");
2556:                        psGroupOptionRemove = con.prepareStatement(sql
2557:                                .toString());
2558:                        sql.setLength(0);
2559:                        sql.append("DELETE FROM ").append(TBL_CONTENT_DATA)
2560:                                .append(" WHERE ASSIGN=?");
2561:                        psData = con.prepareStatement(sql.toString());
2562:                        sql.setLength(0);
2563:                        sql.append("DELETE FROM ").append(TBL_CONTENT_DATA_FT)
2564:                                .append(" WHERE ASSIGN=?");
2565:                        psDataFT = con.prepareStatement(sql.toString());
2566:                        sql.setLength(0);
2567:                        sql.append("SELECT DISTINCT FBLOB FROM ").append(
2568:                                TBL_CONTENT_DATA).append(
2569:                                " WHERE ASSIGN=? AND FBLOB IS NOT NULL");
2570:                        psBinaryGet = con.prepareStatement(sql.toString());
2571:                        sql.setLength(0);
2572:                        sql.append("DELETE FROM ").append(TBL_CONTENT_BINARY)
2573:                                .append(" WHERE ID=?");
2574:                        psBinaryRemove = con.prepareStatement(sql.toString());
2575:                        for (FxAssignment ml : affectedAssignments) {
2576:                            if (!disableAssignment) {
2577:                                psML.setLong(1, ml.getId());
2578:                                psML.addBatch();
2579:                            }
2580:                            if (ml instanceof  FxPropertyAssignment) {
2581:                                psData.setLong(1, ml.getId());
2582:                                psData.addBatch();
2583:                                psDataFT.setLong(1, ml.getId());
2584:                                psDataFT.addBatch();
2585:                                psPropertyOptionRemove.setLong(1, ml.getId());
2586:                                psPropertyOptionRemove.addBatch();
2587:                                //only need to remove binaries if its a binary type...
2588:                                switch (((FxPropertyAssignment) ml)
2589:                                        .getProperty().getDataType()) {
2590:                                case Binary:
2591:                                    psBinaryGet.setLong(1, ml.getId());
2592:                                    ResultSet rs = psBinaryGet.executeQuery();
2593:                                    while (rs != null && rs.next()) {
2594:                                        psBinaryRemove
2595:                                                .setLong(1, rs.getLong(1));
2596:                                        psBinaryRemove.addBatch();
2597:                                    }
2598:                                }
2599:                            } else if (ml instanceof  FxGroupAssignment) {
2600:                                psGroupOptionRemove.setLong(1, ml.getId());
2601:                                psGroupOptionRemove.addBatch();
2602:                            }
2603:                        }
2604:                        if (!disableAssignment) {
2605:                            psML.executeBatch();
2606:                        }
2607:                        psPropertyOptionRemove.executeBatch();
2608:                        psGroupOptionRemove.executeBatch();
2609:                        psBinaryRemove.executeBatch();
2610:                        psDataFT.executeBatch();
2611:                        psData.executeBatch();
2612:                    } finally {
2613:                        if (psML != null)
2614:                            psML.close();
2615:                        if (psData != null)
2616:                            psData.close();
2617:                        if (psDataFT != null)
2618:                            psDataFT.close();
2619:                        if (psBinaryGet != null)
2620:                            psBinaryGet.close();
2621:                        if (psBinaryRemove != null)
2622:                            psBinaryRemove.close();
2623:                    }
2624:
2625:                    List<FxAssignment> remaining = new ArrayList<FxAssignment>(
2626:                            affectedAssignments.size());
2627:                    int removed = 1;
2628:                    SQLException lastEx = null;
2629:                    if (disableAssignment)
2630:                        ps.setBoolean(1, false);
2631:                    while (removed > 0) {
2632:                        removed = 0;
2633:                        for (FxAssignment rm : affectedAssignments) {
2634:                            ps.setLong(disableAssignment ? 2 : 1, rm.getId());
2635:                            try {
2636:                                ps.executeUpdate();
2637:                                removed++;
2638:                            } catch (SQLException e) {
2639:                                lastEx = e;
2640:                                remaining.add(rm);
2641:                            }
2642:                        }
2643:                        affectedAssignments.clear();
2644:                        if (disableAssignment)
2645:                            break;
2646:                        affectedAssignments.addAll(remaining);
2647:                        remaining.clear();
2648:                    }
2649:
2650:                    if (affectedAssignments.size() > 0)
2651:                        throw lastEx;
2652:
2653:                    removeOrphanedProperties(con);
2654:                    removeOrphanedGroups(con);
2655:                    StructureLoader.reload(con);
2656:                    htracker.track(assignment.getAssignedType(),
2657:                            disableAssignment ? "history.assignment.remove"
2658:                                    : "history.assignment.disable", assignment
2659:                                    .getXPath(), assignmentId,
2660:                            removeSubAssignments, removeDerivedAssignments);
2661:                } catch (SQLException e) {
2662:                    ctx.setRollbackOnly();
2663:                    throw new FxRemoveException(LOG, e, "ex.db.sqlError", e
2664:                            .getMessage());
2665:                } catch (FxCacheException e) {
2666:                    ctx.setRollbackOnly();
2667:                    throw new FxRemoveException(LOG, e, "ex.cache", e
2668:                            .getMessage());
2669:                } catch (FxLoadException e) {
2670:                    ctx.setRollbackOnly();
2671:                    throw new FxRemoveException(e);
2672:                } finally {
2673:                    Database.closeObjects(TypeEngineBean.class, con, ps);
2674:                }
2675:
2676:            }
2677:
2678:            /**
2679:             * Find all (directly) derived assignments and flag them as 'regular' assignments and set them as new base
2680:             *
2681:             * @param con        an open and valid connection
2682:             * @param assignment the assignment to 'break'
2683:             * @param sql        query builder
2684:             * @return used ps
2685:             * @throws FxNotFoundException         on errors
2686:             * @throws FxInvalidParameterException on errors
2687:             * @throws java.sql.SQLException       on errors
2688:             */
2689:            private PreparedStatement breakAssignmentInheritance(
2690:                    Connection con, FxAssignment assignment, StringBuilder sql)
2691:                    throws SQLException, FxNotFoundException,
2692:                    FxInvalidParameterException {
2693:                sql.append("UPDATE ").append(TBL_STRUCT_ASSIGNMENTS).append(
2694:                        " SET BASE=? WHERE BASE=?"); // AND TYPEDEF=?");
2695:                PreparedStatement ps = con.prepareStatement(sql.toString());
2696:                ps.setNull(1, Types.NUMERIC);
2697:                ps.setLong(2, assignment.getId());
2698:                int count = 0;
2699:                //'toplevel' fix
2700:                //        for(FxType types: assignment.getAssignedType().getDerivedTypes() ) {
2701:                //            ps.setLong(3, types.getId());
2702:                count += ps.executeUpdate();
2703:                //        }
2704:                LOG.info("Updated " + count
2705:                        + " assignments to become the new base assignment");
2706:                /* sql.setLength(0);
2707:                //now fix 'deeper' inherited assignments
2708:                for(FxType types: assignment.getAssignedType().getDerivedTypes() ) {
2709:                    for( FxType subderived: types.getDerivedTypes())
2710:                        _fixSubInheritance(ps, subderived, types.getAssignment(assignment.getXPath()).getId(), assignment.getId());
2711:                }*/
2712:                ps.close();
2713:                sql.setLength(0);
2714:                return ps;
2715:            }
2716:
2717:            /*private void _fixSubInheritance(PreparedStatement ps, FxType type, long newBase, long assignmentId) throws SQLException, FxInvalidParameterException, FxNotFoundException {
2718:                ps.setLong(1, newBase);
2719:                ps.setLong(2, assignmentId);
2720:                ps.setLong(3, type.getId());
2721:                ps.executeUpdate();
2722:                for( FxType derived: type.getDerivedTypes())
2723:                    _fixSubInheritance(ps, derived, newBase, assignmentId);
2724:            }*/
2725:
2726:            /**
2727:             * Recursively gather all sub assignments of the requested group assignment and add it to the given list
2728:             *
2729:             * @param affectedAssignments list where all sub assignments and the group itself are being put
2730:             * @param ga                  the group assignment to start at
2731:             */
2732:            private void _addSubAssignments(
2733:                    List<FxAssignment> affectedAssignments, FxGroupAssignment ga) {
2734:                affectedAssignments.addAll(ga.getAssignedProperties());
2735:                for (FxGroupAssignment subga : ga.getAssignedGroups()) {
2736:                    affectedAssignments.add(subga);
2737:                    _addSubAssignments(affectedAssignments, subga);
2738:                }
2739:            }
2740:
2741:            /**
2742:             * Remove all properties that are no longer referenced
2743:             *
2744:             * @param con a valid connection
2745:             * @throws SQLException on errors
2746:             */
2747:            protected static void removeOrphanedProperties(Connection con)
2748:                    throws SQLException {
2749:                Statement stmt = null;
2750:                try {
2751:                    stmt = con.createStatement();
2752:                    stmt
2753:                            .executeUpdate("DELETE FROM "
2754:                                    + TBL_STRUCT_PROPERTIES
2755:                                    + ML
2756:                                    + " WHERE ID NOT IN(SELECT DISTINCT APROPERTY FROM "
2757:                                    + TBL_STRUCT_ASSIGNMENTS
2758:                                    + " WHERE APROPERTY IS NOT NULL)");
2759:                    stmt
2760:                            .executeUpdate("DELETE FROM "
2761:                                    + TBL_PROPERTY_OPTIONS
2762:                                    + " WHERE ID NOT IN(SELECT DISTINCT APROPERTY FROM "
2763:                                    + TBL_STRUCT_ASSIGNMENTS
2764:                                    + " WHERE APROPERTY IS NOT NULL)");
2765:                    int removed = stmt
2766:                            .executeUpdate("DELETE FROM "
2767:                                    + TBL_STRUCT_PROPERTIES
2768:                                    + " WHERE ID NOT IN(SELECT DISTINCT APROPERTY FROM "
2769:                                    + TBL_STRUCT_ASSIGNMENTS
2770:                                    + " WHERE APROPERTY IS NOT NULL)");
2771:                    if (removed > 0)
2772:                        LOG.info(removed + " orphaned properties removed.");
2773:                } finally {
2774:                    if (stmt != null)
2775:                        stmt.close();
2776:                }
2777:            }
2778:
2779:            /**
2780:             * Remove all groups that are no longer referenced
2781:             *
2782:             * @param con a valid connection
2783:             * @throws SQLException on errors
2784:             */
2785:            protected static void removeOrphanedGroups(Connection con)
2786:                    throws SQLException {
2787:                Statement stmt = null;
2788:                try {
2789:                    stmt = con.createStatement();
2790:                    stmt.executeUpdate("DELETE FROM " + TBL_STRUCT_GROUPS + ML
2791:                            + " WHERE ID NOT IN(SELECT DISTINCT AGROUP FROM "
2792:                            + TBL_STRUCT_ASSIGNMENTS
2793:                            + " WHERE AGROUP IS NOT NULL)");
2794:                    stmt.executeUpdate("DELETE FROM " + TBL_GROUP_OPTIONS
2795:                            + " WHERE ID NOT IN(SELECT DISTINCT AGROUP FROM "
2796:                            + TBL_STRUCT_ASSIGNMENTS
2797:                            + " WHERE AGROUP IS NOT NULL)");
2798:                    int removed = stmt.executeUpdate("DELETE FROM "
2799:                            + TBL_STRUCT_GROUPS
2800:                            + " WHERE ID NOT IN(SELECT DISTINCT AGROUP FROM "
2801:                            + TBL_STRUCT_ASSIGNMENTS
2802:                            + " WHERE AGROUP IS NOT NULL)");
2803:                    if (removed > 0)
2804:                        LOG.info(removed + " orphaned groups removed.");
2805:                } finally {
2806:                    if (stmt != null)
2807:                        stmt.close();
2808:                }
2809:            }
2810:
2811:            /**
2812:             * {@inheritDoc}
2813:             */
2814:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
2815:            public long save(FxPropertyEdit property)
2816:                    throws FxApplicationException {
2817:                FxPermissionUtils.checkRole(FxContext.get().getTicket(),
2818:                        Role.StructureManagement);
2819:                long returnId = property.getId();
2820:                boolean reload;
2821:                Connection con = null;
2822:                try {
2823:                    con = Database.getDbConnection();
2824:                    reload = updateProperty(con, null, null, property);
2825:                    if (reload)
2826:                        StructureLoader.reload(con);
2827:                } catch (SQLException e) {
2828:                    ctx.setRollbackOnly();
2829:                    throw new FxCreateException(LOG, e, "ex.db.sqlError", e
2830:                            .getMessage());
2831:                } catch (FxCacheException e) {
2832:                    ctx.setRollbackOnly();
2833:                    throw new FxCreateException(e, "ex.cache", e.getMessage());
2834:                } catch (FxLoadException e) {
2835:                    ctx.setRollbackOnly();
2836:                    throw new FxCreateException(e);
2837:                } finally {
2838:                    Database
2839:                            .closeObjects(AssignmentEngineBean.class, con, null);
2840:                }
2841:                return returnId;
2842:            }
2843:
2844:            /**
2845:             * {@inheritDoc}
2846:             */
2847:            @TransactionAttribute(TransactionAttributeType.REQUIRED)
2848:            public long save(FxGroupEdit group) throws FxApplicationException {
2849:                FxPermissionUtils.checkRole(FxContext.get().getTicket(),
2850:                        Role.StructureManagement);
2851:                long returnId = group.getId();
2852:                boolean reload;
2853:                Connection con = null;
2854:                try {
2855:                    con = Database.getDbConnection();
2856:                    reload = updateGroup(con, null, null, group);
2857:                    if (reload)
2858:                        StructureLoader.reload(con);
2859:                } catch (SQLException e) {
2860:                    ctx.setRollbackOnly();
2861:                    throw new FxCreateException(LOG, e, "ex.db.sqlError", e
2862:                            .getMessage());
2863:                } catch (FxCacheException e) {
2864:                    ctx.setRollbackOnly();
2865:                    throw new FxCreateException(e, "ex.cache", e.getMessage());
2866:                } catch (FxLoadException e) {
2867:                    ctx.setRollbackOnly();
2868:                    throw new FxCreateException(e);
2869:                } finally {
2870:                    Database
2871:                            .closeObjects(AssignmentEngineBean.class, con, null);
2872:                }
2873:                return returnId;
2874:            }
2875:
2876:            /**
2877:             * {@inheritDoc}
2878:             */
2879:            public long getPropertyInstanceCount(long propertyId)
2880:                    throws FxDbException {
2881:                Connection con = null;
2882:                PreparedStatement ps = null;
2883:                long count = 0;
2884:                try {
2885:                    con = Database.getDbConnection();
2886:                    ps = con.prepareStatement("SELECT COUNT(*) FROM "
2887:                            + TBL_CONTENT_DATA + " WHERE TPROP=?");
2888:                    ps.setLong(1, propertyId);
2889:                    ResultSet rs = ps.executeQuery();
2890:                    rs.next();
2891:                    count = rs.getLong(1);
2892:                    ps.close();
2893:                } catch (SQLException e) {
2894:                    throw new FxDbException(LOG, e, "ex.db.sqlError", e
2895:                            .getMessage());
2896:                } finally {
2897:                    if (con != null)
2898:                        Database.closeObjects(AssignmentEngineBean.class, con,
2899:                                ps);
2900:                }
2901:                return count;
2902:            }
2903:
2904:            /**
2905:             * {@inheritDoc}
2906:             */
2907:            public long getAssignmentInstanceCount(long assignmentId)
2908:                    throws FxApplicationException {
2909:                Connection con = null;
2910:                PreparedStatement ps = null;
2911:                long count = 0;
2912:                try {
2913:                    con = Database.getDbConnection();
2914:                    ps = con.prepareStatement("SELECT COUNT(*) FROM "
2915:                            + TBL_CONTENT_DATA + " WHERE ASSIGN=?");
2916:                    ps.setLong(1, assignmentId);
2917:                    ResultSet rs = ps.executeQuery();
2918:                    rs.next();
2919:                    count = rs.getLong(1);
2920:                    ps.close();
2921:                } catch (SQLException e) {
2922:                    throw new FxDbException(LOG, e, "ex.db.sqlError", e
2923:                            .getMessage());
2924:                } finally {
2925:                    if (con != null)
2926:                        Database.closeObjects(AssignmentEngineBean.class, con,
2927:                                ps);
2928:                }
2929:                return count;
2930:            }
2931:
2932:            /**
2933:             * Get minimum or maximum multiplicity of properties in content instances for a given property
2934:             *
2935:             * @param con        an open and valid Connection
2936:             * @param propertyId requested property
2937:             * @param minimum    true for minimum, false for maximum
2938:             * @return minimum or maximum multiplicity of properties of instances
2939:             * @throws SQLException on errors
2940:             */
2941:            private long getInstanceMultiplicity(Connection con,
2942:                    long propertyId, boolean minimum) throws SQLException {
2943:                PreparedStatement ps = null;
2944:                long count = 0;
2945:                try {
2946:                    String function = "MIN(XINDEX)";
2947:                    if (!minimum)
2948:                        function = "MAX(XINDEX)";
2949:
2950:                    ps = con.prepareStatement("SELECT " + function + " FROM "
2951:                            + TBL_CONTENT_DATA + " WHERE TPROP=?");
2952:                    ps.setLong(1, propertyId);
2953:                    ResultSet rs = ps.executeQuery();
2954:                    rs.next();
2955:                    count = rs.getLong(1);
2956:                } finally {
2957:                    if (ps != null)
2958:                        ps.close();
2959:                }
2960:                return count;
2961:            }
2962:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.