-showlocation
parameter to the Eclipse executable or modifying the eclipse.ini config file.
journal capturing best practises, patterns and solutions to problems encountered in the design and development of enterprise software.
Monday, 12 December 2011
Multiple Eclipse Workspaces
Wednesday, 12 October 2011
Using Oracle XMLQuery and XML-24509: (Error) Duplicated Definition
Oracle provides some nice features for working with XML. There is the option of using PL/SQL and the DBMS_XMLQUERY package or the corresponding OracleXMLQuery Java class.
The OracleXMLQuery class provides an API to retrieve the results of an SQL query as XML. Therefore, I developed a class which would use the OracleXMLQuery and write the results to a file. The query was defined in a Spring context file and injected along with the javax.sql.DataSource. Now it came to the task of writing a test to validate if my class was working. Following the popular approach of testing with Spring and JUnit, I created a test class and a corresponding test context file.
<Line 43, Column 57>: XML-24509: (Error) Duplicated definition for: 'identifiedType'
The problem was that the Oracle XDK which provides the XML Java classes makes use of the Oracle xmlparserv2.jar file to parse XML. This has issues with parsing Spring XSD files and produces the above errors. Spring relies on Apache xerces library. Therefore the solution in this case was to configure Spring not to use the Oracle xml parser via a system property.
Adding the above code to my test class' @BeforeClass method fixed the issue.
Friday, 19 August 2011
Set up JBPM – Oracle - Tomcat 6
<WatchedResource>WEB-INF/web.xml</WatchedResource> <Transaction factory ="bitronix.tm.BitronixUserTransactionObjectFactory" /> <Resource name="jdbc/testDS1" auth="Container" type="javax.sql.DataSource" maxActive="15" maxIdle="2" maxWait="10000" logAbandoned="true"username="username" password="password" driverClassName=" oracle.jdbc.OracleDriver" url="jdbc:oracle:thin:@yourdatabaseurl:port:db"/> |
resource.ds1.className=bitronix.tm.resource.jdbc.lrc.LrcXADataSource
resource.ds1.uniqueName=jdbc/testDS1 resource.ds1.minPoolSize=0 resource.ds1.maxPoolSize=5 resource.ds1.driverProperties.driverClassName=oracle.jdbc.OracleDriver |
3. Copy oracle ojdbc14.jar into the ‘tomcat/lib’ and ‘jbpm-installer/runtime’ folder for oracle driver.
4. Modify hibernate.cfg.xml in TOMCAT_HOME\webapps\gwt-console-server\WEB-INF\classes\META-INF to include Oracle connection details and comment the h2 details.
Note: Its better to change into the WAR (gwt-console-server.war) itself so can be deployed on different instances.
Replace the session-factory tag from below
<session-factory>
<!-- h2 Database connection settings --> <!--property name="connection.url">jdbc:h2:file:/NotBackedUp /data/mydb</property--> <!-- <property name="connection.driver_class">org.h2.Driver</property> <property name="connection.url">jdbc:h2:tcp://localhost/~/test</ property> <property name="connection.username">sa</property> <property name="connection.password"></property> <property name="connection.pool_size">1</property> <property name="dialect">org.hibernate.dialect.H2Dialect</property> --> <!-- Oracle Database connection settings --> <property name="connection.driver_class"& gt;oracle.jdbc.OracleDriver</property> <property name="connection.url"> jdbc:oracle:thin:@yourdatabaseurl:port:db</property> <property name="connection.username">username</property> <property name="connection.password">password</property> <property name="connection.pool_size">1</property> <property name="dialect">org.hibernate.dialect.Oracle10gDialect</ property> <!-- Enable Hibernate's automatic session context management --> <property name="current_session_context_class">thread& lt;/property> <!-- Disable the second-level cache --> <property name="cache.provider_class"& gt; org.hibernate.cache.NoCacheProvider</property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">false</property> <!-- Drop and re-create the database schema on startup --> <property name="hbm2ddl.auto">create</property> <mapping resource="AuditLog.hbm.xml"/> </session-factory> |
5. Make sure the jbpm-human-task-5.0-SNAPSHOT.jar is in TOMCAT_HOME/webapps/gwt-console-server/WEB-INF/lib (5.1 full installer zip contains this jar in the gwt-console-server web-inf lib) OR if not present then download and copy jbpm-human-task-5.0-SNAPSHOT.jar to TOMCAT_HOME/webapps/gwt-console-server/WEB-INF/lib
6. Make sure the jbpm-bam-5.0-SNAPSHOT.jar is in TOMCAT_HOME/webapps/gwt-console-server/WEB-INF/lib (5.1 full installer zip contains this jar in the gwt-console-server web-inf lib) OR if not present then download and copy copy jbpm-bam-5.0-SNAPSHOT.jar to TOMCAT_HOME/webapps/gwt-console-server/WEB-INF/lib
7. Add or Replace oracle connection details in persistence.xml of TOMCAT_HOME\webapps\gwt-console-server\WEB-INF\classes\META-INF.
<persistence-unit name="org.jbpm.persistence.jpa">
|
<session-factory>
|
Set up the JBPM suite on tomcat 6
2. Change the TOMCAT_HOME, CATALINA_HOME env variable pointing to the new tomcat folder.
3. Download jbpm-5.1.0.Final-installer-full.zip from jboss site unzip into a folder.
a. Go into the lib folder, which will have 6 more files in it. 2 wars and 6 zip files.
4. copy 2 wars into the tomcat-home/webapps. Rename of war is required as per below names otherwise all the applications does not start properly.
a. Rename the designer-1.0.0.052-jboss.war to designer.war
b. Rename the guvnor-distribution-wars-5.2.0.Final-jboss-as-5.1.war to drools-guvnor.war
c. Unzip jbpm-5.1.0.Final-gwt-console.zip into the webapps. This zip contains 2 more wars.
d. Rename jbpm-gwt-console-server-5.1.0.Final.war to gwt-console-server.war
e. Rename jbpm-gwt-console-5.1.0.Final.war to jbpm-console.war
5. At this point, if tomcat is restarted, the complete suit is ready to work on. Go to tomcat manager (localhost:8080) and try launching drools-guvnor and jbpm-console. All the functionality does not work with IE so use firefox. It may ask to install google frame. Accept and continue.
6. To login into jbpm console, create few users into tomcat-users.xml as below.
Thursday, 18 August 2011
Drop all tables from schema
BEGIN
FOR i IN (SELECT table_name FROM user_tables)
LOOP
EXECUTE IMMEDIATE('DROP TABLE ' || user || '.' || i.table_name || ' CASCADE CONSTRAINTS');
END LOOP;
END;
Friday, 15 July 2011
Mercurial: .hgignore and eclipse
Create .hgignore file to your root and add all the files which are required to ignore by mercurial.
example: .hgignore
#-----------------------------------------------------------------------
# Add an entry for .settings folder to ignore
#------------------------------------------------------------------------
syntax: regexp
^common/\.settings$
#----------------------------------------------------------------------------
# Add an entry for target folder to ignore when creating a new module.
# This will ignore all the class files.
#----------------------------------------------------------------------------
syntax: regexp
^common/target$
#-------------------------------------
# Use global syntax
#-------------------------------------
syntax: glob
.obj
.exe
Wednesday, 13 July 2011
Error Solution: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role; no session or session was closed
My DAO method and its test is as follows:
DAOImpl:
public List List try { Query query = em.createNamedQuery("mobileWallet.uiConfigDAO.getUIConfigData"); query.setParameter("activityType", activityType.getValue()); rv = query.getResultList(); } catch (NoResultException nre) { // No record found. } return rv; } |
DAOImplTest:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:/dao-test.xml" }) @Transactional public class UIConfigDAOImplTest { @Autowired private EntityManagerFactory entityManagerFactory; private EntityManager em; @Autowired private UIConfigDAO uiConfigDAO; @Before public void setUp() { em = entityManagerFactory.createEntityManager(); } @After public void tearDown() throws Exception { } @Test public void testGetUIConfigData() { List .getInstance("SELF")); Assert.assertNotNull(list); Assert.assertFalse(list.isEmpty()); Assert.assertEquals("FirstName", list.iterator().next().getValue()); Assert.assertNotNull(list.iterator().next().toString()); } } |
Its bit surprising that Assert.assertEquals("FirstName", list.iterator().next().getValue()); got passed but test failed on the next line.
Reason: Once the Hibernate Session is closed anything that hasn't been loaded, can't be loaded without reattaching your entity to a Hibernate Session. The Session will end once the statement has been executed. If I debug the test method, list has all the values and it works if getValue() is called. But fails on accessing the collection.
Solution: The whole test should be running into a transaction. The easiest way is adding @Transactional at class level. This will put the whole test method in one transaction.
We faced the similar situation when business service was called and the reason was the business service was not under one transaction. The method should be in a transaction where the retrieved collection is used. Always keep the business service in a transaction.
Tuesday, 12 July 2011
Specifying parameters for Mockito unit testing
@Transactional public User registerUser(Map<UIField,String> details) { User user = new User(); List<UIField> identifierTypes = referenceDataService. getUserIdentifierTypeList(); Set<UserDetail> userDetails = new HashSet<UserDetail>(); Set<UserIdentifier> userIdentifiers = new HashSet<UserIdentifier>(); for(UIField key :details.keySet()) { if(isIdentifierField(key,identifierTypes)) { userIdentifiers.add(createUserIdentifier(key, details.get(key))); } else { userDetails.add(createUserDetail(key,details.get(key))); } } user.setUserIdentifiers(userIdentifiers); user.setUserDetails(userDetails); UserStatus status = referenceDataService. getUserStatus("REGISTERED"); user.setUserStatus(status); return userService.createUser(user); } |
As listing 1 shows, the registerUser operation instantiates a User object and populates its properties using the parameters passed to the operation. Now we would like the unit-test to ensure this User instance is correctly constructed and its properties correctly populated so that the userService can persist the user. Listing 2 shows the unit-test.
@Test public void testRegisterUser() { //need a map of the data that is being submitted for registration. Map<UIField,String> data = new HashMap<UIField,String>(); addUIField(data,"MSISDN","07987654321"); addUIField(data,"Firstname","Joe"); addUIField(data,"Lastname","Bloggs"); List<UIField> idFieldList = new ArrayList<UIField>(); idFieldList.add(createUIField("MSISDN")); Mockito.when(referenceDataService.getUserIdentifierTypeList()). thenReturn(idFieldList); UserStatus userStatus = new UserStatus(); userStatus.setValue("REGISTERED"); Mockito.when(referenceDataService.getUserStatus("REGISTERED")). thenReturn(userStatus); registrationService.registerUser(data); ArgumentCaptor<User> argument = ArgumentCaptor.forClass(User.class); Mockito.verify(userService).createUser(argument.capture()); User user = argument.getValue(); Assert.assertNotNull(user); Assert.assertEquals(user.getUserStatus().getValue(),"REGISTERED"); Assert.assertEquals(1, user.getUserIdentifiers().size()); Assert.assertEquals(2, user.getUserDetails().size()); } |
The userService and referenceDataService are mock objects which get injected into the RegistrationService. The concern was how to retrieve the user instance from the registerUser operation so that it can be inspected. For this, Mockito provides the ArgumentCaptor class and its use is highlighted in bold showing how to retrieve the User instance and then carry out further assertions.