Author: alex.guizar(a)jboss.com
Date: 2010-10-27 22:12:59 -0400 (Wed, 27 Oct 2010)
New Revision: 6788
Modified:
jbpm3/branches/jbpm-3.2-soa/core/src/main/java/org/jbpm/persistence/db/DbPersistenceService.java
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/MockSession.java
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/MockSessionFactory.java
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/PersistenceDbServiceTest.java
jbpm3/branches/jbpm-3.2-soa/enterprise-jee5/pom.xml
Log:
JBPM-2964 catch any RuntimeException thrown inside DbPersistenceService wrap-up methods,
not just HibernateException
Modified:
jbpm3/branches/jbpm-3.2-soa/core/src/main/java/org/jbpm/persistence/db/DbPersistenceService.java
===================================================================
---
jbpm3/branches/jbpm-3.2-soa/core/src/main/java/org/jbpm/persistence/db/DbPersistenceService.java 2010-10-27
07:42:18 UTC (rev 6787)
+++
jbpm3/branches/jbpm-3.2-soa/core/src/main/java/org/jbpm/persistence/db/DbPersistenceService.java 2010-10-28
02:12:59 UTC (rev 6788)
@@ -32,13 +32,13 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StaleStateException;
import org.hibernate.Transaction;
-import org.hibernate.cfg.Configuration;
-import org.hibernate.cfg.Environment;
+import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.exception.LockAcquisitionException;
import org.jbpm.JbpmContext;
@@ -162,33 +162,26 @@
}
}
else {
- if (session == null && resolveSession) {
- // initializes the session member
- getSession();
- }
- if (session != null) {
+ // resolve session or return
+ Session session = this.session;
+ if (session != null || resolveSession && (session = getSession()) !=
null) {
+ // get connection from session
connection = session.connection();
/*
- * If the session is using aggressive collection release (as in a CMT
environment),
+ * If the session is using aggressive connection release (as in a CMT
environment),
* the application is responsible for closing the returned connection.
Otherwise, the
* application should not close the connection.
*/
- Configuration configuration = persistenceServiceFactory.getConfiguration();
- String releaseMode =
configuration.getProperty(Environment.RELEASE_CONNECTIONS);
- mustConnectionBeClosed = "after_statement".equals(releaseMode)
- || ("auto".equals(releaseMode) &&
isJtaOrCmtStrategy(configuration));
+ SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor)
session.getSessionFactory();
+ ConnectionReleaseMode releaseMode = sessionFactory.getSettings()
+ .getConnectionReleaseMode();
+ mustConnectionBeClosed = releaseMode == ConnectionReleaseMode.AFTER_STATEMENT;
}
}
}
return connection;
}
- private static boolean isJtaOrCmtStrategy(Configuration configuration) {
- String transactionStrategy =
configuration.getProperty(Environment.TRANSACTION_STRATEGY);
- return transactionStrategy != null
- && (transactionStrategy.indexOf("JTA") != -1 ||
transactionStrategy.indexOf("CMT") != -1);
- }
-
public boolean isTransactionActive() {
return transaction != null && transaction.isActive();
}
@@ -207,18 +200,21 @@
}
public void close() {
+ // flush session
Exception flushException = flushSession();
if (flushException != null) {
- // JBPM-1465: enabling transaction disables flush, see beginTransaction()
- // alternatively, transaction is managed externally
- // in either case, rolling back is unnecessary and possibly disruptive
+ // JBPM-1465: if transaction is enabled, flush is disabled, see beginTransaction()
+ // otherwise, transaction is managed externally
+ // in either case, rolling back is unnecessary and possibly disastrous
closeSession();
closeConnection();
throw new JbpmPersistenceException("failed to flush hibernate session",
flushException);
}
+ // commit or roll back transaction
endTransaction();
+ // close session
Exception closeSessionException = closeSession();
if (closeSessionException != null) {
closeConnection();
@@ -226,6 +222,7 @@
closeSessionException);
}
+ // close jdbc connection
Exception closeConnectionException = closeConnection();
if (closeConnectionException != null) {
throw new JbpmPersistenceException("failed to close hibernate
connection",
@@ -238,7 +235,7 @@
try {
transaction.commit();
}
- catch (HibernateException e) {
+ catch (RuntimeException e) {
return e;
}
}
@@ -254,7 +251,7 @@
try {
transaction.rollback();
}
- catch (HibernateException e) {
+ catch (RuntimeException e) {
return e;
}
}
@@ -267,7 +264,7 @@
try {
session.flush();
}
- catch (HibernateException e) {
+ catch (RuntimeException e) {
return e;
}
}
@@ -284,7 +281,7 @@
try {
session.close();
}
- catch (HibernateException e) {
+ catch (RuntimeException e) {
return e;
}
}
@@ -301,6 +298,9 @@
try {
connection.close();
}
+ catch (RuntimeException e) {
+ return e;
+ }
catch (SQLException e) {
return e;
}
@@ -313,14 +313,17 @@
}
public void assignId(Object object) {
- try {
- getSession().save(object);
+ Session session = getSession();
+ if (session != null) {
+ try {
+ session.save(object);
+ }
+ catch (HibernateException e) {
+ // NOTE that Errors are not caught because that might halt the JVM
+ // and mask the original Error.
+ throw new JbpmPersistenceException("could not assign id to " + object,
e);
+ }
}
- catch (HibernateException e) {
- // NOTE that Errors are not caught because that might halt the JVM
- // and mask the original Error.
- throw new JbpmPersistenceException("could not assign id to " + object,
e);
- }
}
// getters and setters //////////////////////////////////////////////////////
@@ -374,9 +377,13 @@
if (customSession != null) return customSession;
}
try {
- Constructor constructor = sessionClass.getConstructor(new Class[] { Session.class
});
+ Constructor constructor = sessionClass.getConstructor(new Class[] {
+ Session.class
+ });
try {
- Object customSession = constructor.newInstance(new Object[] { session });
+ Object customSession = constructor.newInstance(new Object[] {
+ session
+ });
customSessions.put(sessionClass, customSession);
return customSession;
}
@@ -526,6 +533,10 @@
this.isTransactionEnabled = isTransactionEnabled;
}
+ /**
+ * Tells whether the given exception or any of its causes is a persistence exception.
+ * Currently a <em>persistence exception</em> is an instance of {@link
HibernateException}.
+ */
public static boolean isPersistenceException(Exception exception) {
for (Throwable t = exception; t != null; t = t.getCause()) {
if (t instanceof HibernateException) return true;
@@ -533,6 +544,12 @@
return false;
}
+ /**
+ * Tells whether the given exception or any of its causes is a locking exception.
Currently a
+ * <em>locking exception</em> is an instance of {@link StaleStateException}
or
+ * {@link LockAcquisitionException}. Note that Hibernate dialects have limited ability
to map
+ * native locking error codes to {@link LockAcquisitionException}s.
+ */
public static boolean isLockingException(Exception exception) {
for (Throwable t = exception; t != null; t = t.getCause()) {
if (t instanceof StaleStateException || t instanceof LockAcquisitionException) {
Modified:
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/MockSession.java
===================================================================
---
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/MockSession.java 2010-10-27
07:42:18 UTC (rev 6787)
+++
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/MockSession.java 2010-10-28
02:12:59 UTC (rev 6788)
@@ -26,19 +26,23 @@
private static final long serialVersionUID = 1L;
- MockTransaction transaction = null;
- Connection connection = null;
- boolean isFlushed = false;
- boolean isClosed = false;
+ final Connection connection;
+ final SessionFactory sessionFactory;
+ MockTransaction transaction;
+ boolean isFlushed;
+ boolean isClosed;
+
boolean failOnFlush;
boolean failOnClose;
- public MockSession() {
+ public MockSession(SessionFactory sessionFactory) {
+ this(sessionFactory, null);
}
- public MockSession(Connection connection) {
+ public MockSession(SessionFactory sessionFactory, Connection connection) {
this.connection = connection;
+ this.sessionFactory = sessionFactory;
}
public void setFailOnFlush(boolean fail) {
@@ -106,7 +110,7 @@
}
public SessionFactory getSessionFactory() {
- throw new UnsupportedOperationException();
+ return sessionFactory;
}
public void cancelQuery() throws HibernateException {
Modified:
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/MockSessionFactory.java
===================================================================
---
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/MockSessionFactory.java 2010-10-27
07:42:18 UTC (rev 6787)
+++
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/MockSessionFactory.java 2010-10-28
02:12:59 UTC (rev 6788)
@@ -7,25 +7,54 @@
import javax.naming.NamingException;
import javax.naming.Reference;
+import javax.transaction.TransactionManager;
+import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
-import org.hibernate.SessionFactory;
+import org.hibernate.MappingException;
import org.hibernate.StatelessSession;
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.QueryCache;
+import org.hibernate.cache.UpdateTimestampsCache;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Settings;
import org.hibernate.classic.Session;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
import org.hibernate.engine.FilterDefinition;
+import org.hibernate.engine.NamedQueryDefinition;
+import org.hibernate.engine.NamedSQLQueryDefinition;
+import org.hibernate.engine.ResultSetMappingDefinition;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.query.QueryPlanCache;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.id.IdentifierGenerator;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.metadata.CollectionMetadata;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.stat.Statistics;
+import org.hibernate.stat.StatisticsImplementor;
+import org.hibernate.type.Type;
-public class MockSessionFactory implements SessionFactory {
+public class MockSessionFactory implements SessionFactoryImplementor {
+ private Settings settings;
private boolean failOnFlush;
private boolean failOnClose;
private boolean isClosed;
private static final long serialVersionUID = 1L;
+ public MockSessionFactory() {
+ Configuration configuration = new Configuration();
+ configuration.configure();
+ settings = configuration.buildSettings();
+ }
+
public void setFailOnFlush(boolean fail) {
failOnFlush = fail;
}
@@ -35,14 +64,14 @@
}
public Session openSession(Connection connection) {
- MockSession session = new MockSession(connection);
+ MockSession session = new MockSession(this, connection);
session.setFailOnFlush(failOnFlush);
session.setFailOnClose(failOnClose);
return session;
}
public Session openSession() throws HibernateException {
- MockSession session = new MockSession();
+ MockSession session = new MockSession(this);
session.setFailOnFlush(failOnFlush);
session.setFailOnClose(failOnClose);
return session;
@@ -145,4 +174,131 @@
public Reference getReference() throws NamingException {
throw new UnsupportedOperationException();
}
+
+ public Map getAllSecondLevelCacheRegions() {
+ throw new UnsupportedOperationException();
+ }
+
+ public CollectionPersister getCollectionPersister(String role) throws MappingException
{
+ throw new UnsupportedOperationException();
+ }
+
+ public Set getCollectionRolesByEntityParticipant(String entityName) {
+ throw new UnsupportedOperationException();
+ }
+
+ public ConnectionProvider getConnectionProvider() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Dialect getDialect() {
+ throw new UnsupportedOperationException();
+ }
+
+ public EntityNotFoundDelegate getEntityNotFoundDelegate() {
+ throw new UnsupportedOperationException();
+ }
+
+ public EntityPersister getEntityPersister(String entityName) throws MappingException {
+ throw new UnsupportedOperationException();
+ }
+
+ public IdentifierGenerator getIdentifierGenerator(String rootEntityName) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getImplementors(String className) throws MappingException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getImportedClassName(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Interceptor getInterceptor() {
+ throw new UnsupportedOperationException();
+ }
+
+ public NamedQueryDefinition getNamedQuery(String queryName) {
+ throw new UnsupportedOperationException();
+ }
+
+ public NamedSQLQueryDefinition getNamedSQLQuery(String queryName) {
+ throw new UnsupportedOperationException();
+ }
+
+ public QueryCache getQueryCache() {
+ throw new UnsupportedOperationException();
+ }
+
+ public QueryCache getQueryCache(String regionName) throws HibernateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public QueryPlanCache getQueryPlanCache() {
+ throw new UnsupportedOperationException();
+ }
+
+ public ResultSetMappingDefinition getResultSetMapping(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getReturnAliases(String queryString) throws HibernateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Type[] getReturnTypes(String queryString) throws HibernateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public SQLExceptionConverter getSQLExceptionConverter() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Cache getSecondLevelCacheRegion(String regionName) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Settings getSettings() {
+ return settings;
+ }
+
+ public SQLFunctionRegistry getSqlFunctionRegistry() {
+ throw new UnsupportedOperationException();
+ }
+
+ public StatisticsImplementor getStatisticsImplementor() {
+ throw new UnsupportedOperationException();
+ }
+
+ public TransactionManager getTransactionManager() {
+ throw new UnsupportedOperationException();
+ }
+
+ public UpdateTimestampsCache getUpdateTimestampsCache() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Session openSession(Connection connection, boolean
flushBeforeCompletionEnabled,
+ boolean autoCloseSessionEnabled, ConnectionReleaseMode connectionReleaseMode)
+ throws HibernateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Session openTemporarySession() throws HibernateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getIdentifierPropertyName(String className) throws MappingException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Type getIdentifierType(String className) throws MappingException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Type getReferencedPropertyType(String className, String propertyName)
+ throws MappingException {
+ throw new UnsupportedOperationException();
+ }
}
Modified:
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/PersistenceDbServiceTest.java
===================================================================
---
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/PersistenceDbServiceTest.java 2010-10-27
07:42:18 UTC (rev 6787)
+++
jbpm3/branches/jbpm-3.2-soa/core/src/test/java/org/jbpm/persistence/db/PersistenceDbServiceTest.java 2010-10-28
02:12:59 UTC (rev 6788)
@@ -10,14 +10,12 @@
JbpmConfiguration jbpmConfiguration;
JbpmContext jbpmContext;
- MockSessionFactory mockSessionFactory;
protected void setUp() throws Exception {
super.setUp();
jbpmConfiguration =
JbpmConfiguration.parseXmlString("<jbpm-configuration/>");
jbpmContext = jbpmConfiguration.createJbpmContext();
- mockSessionFactory = new MockSessionFactory();
- jbpmContext.setSessionFactory(mockSessionFactory);
+ jbpmContext.setSessionFactory(new MockSessionFactory());
}
protected void tearDown() throws Exception {
Modified: jbpm3/branches/jbpm-3.2-soa/enterprise-jee5/pom.xml
===================================================================
--- jbpm3/branches/jbpm-3.2-soa/enterprise-jee5/pom.xml 2010-10-27 07:42:18 UTC (rev
6787)
+++ jbpm3/branches/jbpm-3.2-soa/enterprise-jee5/pom.xml 2010-10-28 02:12:59 UTC (rev
6788)
@@ -1,119 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ====================================================================== -->
+<!-- jBPM: Workflow in Java -->
+<!-- -->
+<!-- Distributable under LGPL license. -->
+<!-- See terms of license at
http://www.gnu.org. -->
+<!-- ====================================================================== -->
+
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <name>jBPM3 - JEE5 Enterprise</name>
- <groupId>org.jbpm.jbpm3</groupId>
- <artifactId>jbpm-enterprise-jee5</artifactId>
- <packaging>ejb</packaging>
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <name>jBPM3 - JEE5 Enterprise</name>
+ <groupId>org.jbpm.jbpm3</groupId>
+ <artifactId>jbpm-enterprise-jee5</artifactId>
+ <packaging>ejb</packaging>
- <parent>
- <groupId>org.jbpm.jbpm3</groupId>
- <artifactId>jbpm</artifactId>
- <version>3.2.10-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
+ <parent>
+ <groupId>org.jbpm.jbpm3</groupId>
+ <artifactId>jbpm</artifactId>
+ <version>3.2.10-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- <target>1.5</target>
- </configuration>
- </plugin>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
- <plugin>
- <artifactId>maven-javadoc-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- </configuration>
- </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ </configuration>
+ </plugin>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>assembly-config</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>scripts/assembly-config.xml</descriptor>
- </descriptors>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- <profiles>
- <profile>
- <id>soa4x</id>
-
- <activation>
- <activeByDefault>true</activeByDefault>
- </activation>
- <build>
- <finalName>${project.artifactId}-${project.version}-soa4x.jar</finalName>
- <resources>
- <resource>
- <directory>src/main/resources</directory>
- <excludes>
- <exclude>*soa5x*</exclude>
- </excludes>
- </resource>
- </resources>
- </build>
- </profile>
- <profile>
- <id>soa5x</id>
- <activation>
- <activeByDefault>false</activeByDefault>
- </activation>
- <build>
- <finalName>${project.artifactId}-${project.version}-soa5x.jar</finalName>
- <resources>
- <resource>
- <directory>src/main/resources</directory>
- <excludes>
- <exclude>*soa5x*</exclude>
- </excludes>
- </resource>
- </resources>
- </build>
- </profile>
- </profiles>
- <dependencies>
- <dependency>
- <groupId>org.jbpm.jbpm3</groupId>
- <artifactId>jbpm-jpdl</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>javax.jms</groupId>
- <artifactId>jms</artifactId>
- <version>1.1</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.ejb</groupId>
- <artifactId>ejb-api</artifactId>
- <version>3.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.annotation</groupId>
- <artifactId>jsr250-api</artifactId>
- <version>1.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <scope>provided</scope>
- </dependency>
- </dependencies>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assembly-config</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>scripts/assembly-config.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jbpm.jbpm3</groupId>
+ <artifactId>jbpm-jpdl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.jms</groupId>
+ <artifactId>jms</artifactId>
+ <version>1.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.ejb</groupId>
+ <artifactId>ejb-api</artifactId>
+ <version>3.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.annotation</groupId>
+ <artifactId>jsr250-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>soa4x</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <build>
+
<finalName>${project.artifactId}-${project.version}-soa4x.jar</finalName>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <excludes>
+ <exclude>*soa5x*</exclude>
+ </excludes>
+ </resource>
+ </resources>
+ </build>
+ </profile>
+
+ <profile>
+ <id>soa5x</id>
+ <build>
+
<finalName>${project.artifactId}-${project.version}-soa5x.jar</finalName>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <excludes>
+ <exclude>*soa5x*</exclude>
+ </excludes>
+ </resource>
+ </resources>
+ </build>
+ </profile>
+ </profiles>
</project>