Service Model – Access Service

Access Services are designed specifically to proxy a 3rd party web service or API. In the realm of proxying a 3rd party web service, this is related to the pattern called Legacy Wrapper. The goal of this is to expose a Canonical Model to the enterprise or other services instead of the legacy model that is provided from the legacy application. This keeps the legacy application’s model from bleeding into the architecture, which allows for isolating the legacy service and provide the potentiality for replacing the service at a later date.

The Access Service is therefore responsible for doing mediation between the Canonical Model and the Legacy Model. This mediation can be done with different technologies and in different languages.

ESB Based Solutions for Mediation
Writing a Mediator in WSO2 ESB – Part I
XSLT transformations in Oracle Service Bus

Java Based Solutions for Mediation
Dozer is a Java Bean to Java Bean mapper

Obviously we can just write Java logic to walk the object graph of one messaging model and map it to another messaging model. This isn’t ideal, but the benefit is we don’t have to learn how to use a new API in order to do this, and we don’t have to run an ESB in order to provide mediation (see the Guerilla SOA presentation on InfoQ).

Because the services are 3rd party services or legacy services, there are no rules applied to the naming of operations within the contract. There are requirements around the naming of a service, as these services should have a suffix of AccessService. And if the internal framework proxies an external service call, then this service will have a suffix of ProxyService. This helps to identify how these services were developed and that there specific goal is to hide contracts that are not under enterprise control or are generated from legacy technology.

There is no special handling in the development of these services from a technology or framework perspective, unless the Access Service is a proxy for a remoting technology such as an EJB or RMI call where the Spring Integration Framework will be used to make these external calls. Spring/CXF will also be used with JAX-RS to invoke 3rd Party services that require an XML over HTTP capability.

For Java based endpoint development, a 3rd Party/Legacy web service can be integrated with by generating a client off of the WSDL, or we can create Java Interfaces (with JAX-WS annotations) and a model that represents the external model (with JAXB annotations). We can then use CXF’s JaxWsProxyFactoryBean to invoke the service (without an implementation), because this class can scan the JAX-WS/JAXB annotations from our interface/model in order to make the SOAP invocation.

As mentioned earlier, with Oracle Service Bus development, we would install our 3rd Party/Legacy WSDL and service configuration it as a Business Service. We would then develop a WSDL/Schema based on our enterprise requirements and Canonical Model and configure this as a Proxy Service (Proxy/Business Service in this aspect are Oracle Service Bus specific terms). Then a mediation or routing plan would be created in connecting the Proxy and Business Service together. Steps could be configured within the in/out pipelines to add an XSLT or XQuery transformation between the two Schema models, essentially providing the mediation layer.

These are both two different types of approaches that can be used to create these Access Services, and the decision may lay specifically with whether an ESB is available to assist in the integration, or because of time and technology skill set, it is just easier to do the development within Java.

Share and Enjoy

Hibernate and JPA 2.0 with WebLogic Server

I talked a little about utilizing Hibernate/JPA 2 with WebLogic Server in my blog about (Multiple persistence.xml files and JPA). First off, the idea was to utilize JPA 2 and use Hibernate as the provider so that all the persistence logic could be written against JPA. Long-term, this was a mistake, since Hibernate has such advanced features such as their Filters and Interceptors that Hibernate’s API began to slowly creep into the core persistence classes we developed. So even though the initial concept seemed ideal to have this separation where the persistence provider would be hidden from application logic, that quickly changed and it became apparent that much time and effort would have been saved in just using Hibernate as opposed to coupling it with JPA 2.

That being said, in order to get Hibernate to work in WebLogic Server, one of the simplest things to do is create a preclasspath directory that we can place in front of WebLogic libraries in the WebLogic Server startup script. Then additional libraries can be added to this folder that are necessary to implement features where library collisions occur with WebLogic Server weblogic.jar and other default jars (such as saaj-impl.jar). Since the weblogic.jar contains many 3rd party libraries, and older versions than we like to use, we have to place the antlr jar in this preclasspath directory (along with other ones such as commons-lang.jar and saaj-impl.jar). Once we start our WebLogic Server, we start getting errors related to this Oracle Forum post (Thread: Hibernate 3.6 Final (JPA 2.0) + WL 10.3.x :Unable to deploy sample appn) and Can not deploy 3.5 to Weblogic 10.3 server. The error is basically:

1
java.lang.Throwable: java.lang.NoSuchMethodError: javax.persistence.spi.PersistenceUnitInfo.getValidationMode()Ljavax/persistence/ValidationMode;

The way to simply resolve this is by putting the “hibernate-jpa-2.0-api-1.0.1.Final.jar” into the preclasspath folder in WebLogic Server and restart the server. This appeared to fix the issue, until we actually started doing testing later on in other environments related to the Validation Framework. The following error began to appear (ignore the jar names, I use Apache Shade to combine the multiple hibernate jars into a single jar):

1
2
3
4
5
6
7
8
9
10
11
java.lang.AbstractMethodError: null        
at javax.persistence.Persistence$1.isLoaded(Persistence.java:93) ~[hibernate-jpa-2.0-api-1.0.1.Final.jar:1.0.1.Final]        
at org.hibernate.validator.engine.resolver.JPATraversableResolver.isReachable(JPATraversableResolver.java:61) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.resolver.DefaultTraversableResolver.isReachable(DefaultTraversableResolver.java:131) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.resolver.SingleThreadCachedTraversableResolver.isReachable(SingleThreadCachedTraversableResolver.java:46) ~[hibernate-full.jar:3.6.9]
at org.hibernate.validator.engine.ValidatorImpl.isValidationRequired(ValidatorImpl.java:1242) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:448) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:397) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:361) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:313) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.ValidatorImpl.validate(ValidatorImpl.java:139) ~[hibernate-full.jar:3.6.9]

The next step was to upgrade the Hibernate Validator framework jars and also attempt to upgrade the Hibernate jars, but this did not seem to alleviate our issues. Plus, the phase of the project did not allow the upgrade from a Hibernate 3.6.0 to the newer Hibernate 4.* without some serious regression. So with some additional research, the issue seemed to really resolve around what implementation classes were being forced down the WebLogic Server classpath, as opposed to the libraries that were being supplied within the WAR. The following two links were discussions that related to this issue:

@Valid annotation gives java.lang.AbstractMethodError
AbstractMethodError in WebLogic 10.3.4
Validator fails when a non-Hibernate persistence layer is in the classpath

So through these discussions as well as a few other threads that I cannot seem to find now, the resolution was to get rid of the preclasspath library of hibernate-jpa-2.0-api-1.0.1.Final.jar and replace that jar with another spec reference from Geronimo called geronimo-jpa_2.0_spec-1.1.jar. With this replacement, the JPA 2.0 functionality continued to work because of the provided interfaces within the Geronimo API, and the AbstractMethodError disappeared when utilizing the Validator Framework functionality.

Share and Enjoy

JPA (Hibernate) Field Name Issues

I am using Hibernate 3.6, JPA 2.0, and Spring 3.0.6. Hibernate configuration files are being used instead of annotations on the model classes because we like the separation of the configuration files so that the models don’t carry Hibernate library dependencies. These classes utilize standard POJO/Bean definitions with field names and getters/setters for each field, utilizing Hibernate’s Field Access. Here is a sample of the class and orm file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
 * This is a generated class. Do not modify.
 */

@XmlRootElement(namespace = "http://foo.com/model", name = "ElectronicAddress")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(namespace = "http://foo.com/model", name = "ElectronicAddress", propOrder = { "eAddress", "id" })
public class ElectronicAddress extends ContactPoint {

    /**
     * The serialize value.
     */

    private static final long serialVersionUID = -1L;
    /**
     * The eAddress field.
     */

    @XmlElement(name = "EAddress", namespace = "##default")
    private String eAddress;
    /**
     * The id field.
     */

    @XmlElement(name = "Id", namespace = "##default")
    private Long id; //NOPMD

    /**
     * Gets the value of the eAddress property.
     * This field is Required.
     *
     * @return eAddress object is {@link String }
     */

    public String getEAddress() {
        return eAddress;
    }

    /**
     * Sets the value of the eAddress property.
     * This field is Required
     *
     * @param eAddress object is {@link String }
     */

    public void setEAddress(String eAddress) {
        this.eAddress = eAddress;
    }

    /**
     * Gets the value of the id property.
     * This field is Optional.
     *
     * @return id object is {@link Long }
     */

    public Long getId() {
        return id;
    }

    /**
     * Sets the value of the id property.
     * This field is Optional
     * genericInheritGetterSetter
     * @param id object is {@link Long }
     */

    public void setId(Long id) {
        this.id = (Long) id;
    }

}

The following is the orm file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
  http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"

    version="2.0">
    <description>com.foo.model.ElectronicAddress Entity Mapping</description>
    <package>com.foo.model</package>
    <schema>COMMON</schema>
    <access>FIELD</access>
    <entity class="com.foo.model.ElectronicAddress"
        access="FIELD" metadata-complete="true">
        <table name="ELECTRONIC_ADDRESSES" />
        <attributes>
            <id name="id">
                <column name="ELECTRONIC_ADDRESS_ID" />
                <generated-value strategy="SEQUENCE" generator="ADDR_SEQ" />
                <sequence-generator name="ADDR_SEQ"
                    sequence-name="COMMON.ADDR_SEQ" allocation-size="1" />
            </id>
            <basic name="eAddress">
                <column name="ELECTRONIC_ADDRESS" />
            </basic>
        </attributes>
    </entity>
</entity-mappings>

When the application is deployed to the WebLogic Server, there are quite a few WARN statements that appear related to some of the properties that are defined within the orm files. The interesting thing is that the WARN messages only appear with relation to field names that have a single lowercase character, and these WARN messages don’t appear to change/effect any of the running application.

1
2
3
4
5
2011-02-22 15:38:10,785 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.contactpoint.ElectronicAddress.eAddress not found in class but described in  (possible typo error)
2011-02-22 15:38:10,801 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PersonContact.eAddressCpId not found in class but described in  (possible typo error)
2011-02-22 15:38:10,801 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PersonContact.eAddress not found in class but described in  (possible typo error)
2011-02-22 15:38:10,817 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PartyContact.eAddressCpId not found in class but described in  (possible typo error)
2011-02-22 15:38:10,817 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PartyContact.eAddress not found in class but described in  (possible typo error)

After posting this to Stackoverflow.com under (In Hibernate/JPA can field names no begin with a single letter camel case?), I was pointed to the JPAOverridenAnnotationReader class.

When we take a look at the class JPAOverridenAnnotationReader, we find a method called checkForOrphanProperties

1
2
3
4
5
6
7
8
9
for (Method method : clazz.getMethods()) {
    String name = method.getName();
    if ( name.startsWith( "get" ) ) {
        properties.add( Introspector.decapitalize( name.substring( "get".length() ) ) );
    }
    else if ( name.startsWith( "is" ) ) {
        properties.add( Introspector.decapitalize( name.substring( "is".length() ) ) );
    }
}

The problem is that the method looks for all public fields and then starts adding field names based on “get” and “is” methods it finds. The Introspector.decapitalize method utilizes specific rules to determine what to decapitalize.

From the Introspector class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * Utility method to take a string and convert it to normal Java variable
 * name capitalization.  This normally means converting the first
 * character from upper case to lower case, but in the (unusual) special
 * case when there is more than one character and both the first and
 * second characters are upper case, we leave it alone.
 * <p>
 * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
 * as "URL".
 *
 * @param  name The string to be decapitalized.
 * @return  The decapitalized version of the string.
 */

public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
    return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
        Character.isUpperCase(name.charAt(0))){
    return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}

The result is that the decapitalize method doesn’t work the way we expect based on how our field name/setter/getter methods are cased.

1
private String eAddress;

And our getter is:

1
2
3
public String getEAddress() {
        return eAddress;
}

So based on the Introspector.decapitalize functionality, the result of the decapitalize would be “EAddress”, not “eAddress”. Because it sees two capital letters in the “EAddress” when the code substrings off the “get”…it won’t decapitalize those. Therefore it complains that the eAddress field in the orm.xml doesn’t exist. The persistence of the field works totally fine, these warnings just show up when the war starts and the files are bootstrapped.

Share and Enjoy