Architecture

Service Layer and Model Design

When designing services, it is important to create categories that the different types of service requirements fall into. This allows us to establish standards, best practices, and reference implementations for those types of services. Also, we can better understand the problem domain by understanding the service requirement and then being able to apply a solution for all services within that service layer.

Two of the better books for service layers and models are:

These books refer to concepts (such as Thomas Erl talks about at http://serviceorientation.com), three types of service layers called task service layer, entity service layer, utility service layer. You can find an explanation for these at the following site:

ServiceOrientation.com – Service Layers

We can see a similar concept when reading the Oracle SOA Reference Architecture, the following diagram is a representation of that from a technical article. It classifies different service layers and the types of services that exist.

OracleSOAReferenceArchitecture
A Guide to Ensuring the Success of Your SOA Governance

There is also a similar reference or description within the Oracle AIA (Application Integration Architecture) documentation:

OraclesAIASharedServicesInventory
Understanding the Oracle AIA Reference Architecture

The interesting thing about reading through the materials, is that the concept of designing services or web services is no different from designing proper APIs. The issue is that as teams are new to the concept of designing services, the concept seems foreign and therefore is treated totally different from API design (which is probably a reflection of sloppy API design). So taking these suggested categories, and the concepts for strategies that are used for Java Application development we can define some generic service types.

The following are the types and these services are based on a functional role, some standards that help drive how they are developed, what dependencies they have, and what standards are applied to them.

  1. Access Service
  2. Utility Service
  3. Data Service
  4. Search Service
  5. Messaging Service
  6. Subscribe Service
  7. Business Service

This blog is a work in progress and I will continue to update with additional information.

Share and Enjoy

WebLogic Optional Packages and Dependency Maturity

So I mentioned in another post about a Dependency Maturity Model where I will pull the environmental properties from our WAR deployments. The way I accomplish this with WebLogic is by making the jar file that holds the environmental property like an OSGi bundle for WebLogic (which is an optional package). This is not a very complex exercise, it is really about giving a JAR information with it’s MANIFEST.MF to identify it’s versions and a JAR key, then referencing that within deployments that use the JAR (like a WAR).

I configure the maven-jar-plugin to put additional information to the MANIFEST.MF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifestEntries>
                <Manifest-Version>1.0</Manifest-Version>
                <Extension-Name>envProperties</Extension-Name>
                <Specification-Version>${env.spec.version}</Specification-Version>
                <Implementation-Version>${env.impl.version}</Implementation-Version>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

Once this JAR is built through our Maven project, I need to deploy it out to WebLogic utilizing the maven-weblogic-plugin (for WLS 11). There are two interesting pieces of information regarding the link to the WebLogic Server 11 and WebLogic Server 12 versions of the plugin. The WebLogic Server 12 version appears to have a bug and does not support deploying libraries at all and therefore I have to utilize the WebLogic Server 11 version of the maven plugin. The second issue though is that the WebLogic Server 11 version of the plugin does not support the library capability through XML, it has to be supplied as a command line argument.

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
<plugin>
    <groupId>com.oracle.weblogic</groupId>
    <artifactId>weblogic-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>deploy</id>
            <phase>compile</phase>
            <goals>
                <goal>deploy</goal>
            </goals>
            <configuration>
                <adminurl>t3://${target.hostname}:${target.port}</adminurl>
                <user>${target.userId}</user>
                <password>${target.password}</password>
                <upload>true</upload>
                <action>deploy</action>
                <targets>${target.cluster}</targets>
                <remote>true</remote>
                <verbose>true</verbose>
                <library>true</library>
                <source>${project.build.directory}/lib/${property.name}.jar</source>
                <name>envProperties</name>
            </configuration>
        </execution>
    </executions>
</plugin>

So the main piece of configuration here that differentiates this from a normal WAR or EAR deployment is the true. This XML element is supposed to identify this deployment as an Optional Package, but this field does not work. In order to bypass this error, when I run the maven goal to fire off this plugin, I have to pass in a -Dlibrary=true for this resource to successfully deploy as an Optional Package (otherwise WebLogic will generate an error that this is an invalid resource type).

The next step is to make modifications to our WAR so that it can become aware of the Optional Package. I do this by modifying a maven plugin so that it can build references in the WAR’s MANIFEST.MF to the JAR’s MANIFEST.MF.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
        <archive>
            <manifestEntries>
                <Manifest-Version>1.0</Manifest-Version>
                                           
                <Extension-List>envProperties cxfFull</Extension-List>
                <envProperties-Extension-Name>envProperties</envProperties-Extension-Name>
                <envProperties-Specification-Version>${env.spec.version}</envProperties-Specification-Version>
                <envProperties-Implementation-Version>${env.spec.version}</envProperties-Implementation-Version>
                                           
                <cxfFull-Extension-Name>cxfFull</cxfFull-Extension-Name>
                <cxfFull-Implementation-Version>${cxfFull.spec.version}</cxfFull-Implementation-Version>
                <cxfFull-Specification-Version>${cxfFull.spec.version}</cxfFull-Specification-Version>
            </manifestEntries>
        </archive>
        <packagingExcludes>WEB-INF/lib/cxf*.jar</packagingExcludes>
    </configuration>
</plugin>

There are some additional interesting items that I have in this configuration that I can go over, but let’s first talk about how I reference the environment property JAR.

1
2
3
4
<Extension-List>envProperties cxfFull</Extension-List>
<envProperties-Extension-Name>envProperties</envProperties-Extension-Name>
<envProperties-Specification-Version>${env.spec.version}</envProperties-Specification-Version>
<envProperties-Implementation-Version>${env.spec.version}</envProperties-Implementation-Version>

In the Extension-List tag, I list all the *-Extension-Name configurations that I have. So in the previous section of the configuration, I have an envProperties-Extension-Name=envProperties and a cxfFull-Extension-Name=cxfFull. I therefore need to list these values in the Extension-List element. The next step is to reference the Implementation/Specification Versions and I do this by using the *-Extension-Name value as the key in the name of the configuration. So if our key is envProperties, our *-Extension-Name becomes envProperties-Extension-Name, our *-Specification-Version becomes envProperties-Specification-Version, and our *-Implementation-Version becomes envProperties-Implementation-Version.

The other important piece of configuration here is the . I utilize this feature to remove jars (that I have designated as Optional Packages) so that they will not be included into the built war file. The reason for this again is that these jars will be available via Optional Packages and therefore I remove them from the war and therefore reduce the size of the war and increase performance for startup/deployment.

Now that I have been able to create the reference between the two, once the WAR is deployed, it will create a link between it and the environment properties JAR. In fact, if I log into our WebLogic console and click on our environment properties deployment and I can see all the other deployments that are using it. These relationships will be listed under the “Applications that reference this Library” table.

Because of this relationship, anytime I need to redeploy the environmental properties jar or any Optional Package, I will need to start/stop the web applications that use the specific Optional Package. This allows that web application to reload the new changes to the Optional Package (unfortunately it does not appear to be dynamic), but it also does not require us to restart the Admin/Managed Server instances.

For more additional information about the weblogic-maven-plugin, see my other post as to how I deploy wars using this plugin.

Share and Enjoy

Simplifying Build Management – Build Once, Deploy Anywhere

With many types of languages and approaches to development, it becomes apparent that there are also different approaches to build management of artifacts/resources regardless of language. The diagram below is mainly to provide a picture of how deployment artifacts are tightly coupled to the environments in which they run and how to improve build management. This can be done by moving the deployment artifacts towards a more agnostic view of the environment to which they are deployed. Many times what happens is either applications hard code environment specific properties or environmental properties are built into the final deployment artifact.

The following diagram is an explanation of three levels of a “Dependency Maturity Model” that is used to determine how to move the current applications from Level 1 up to Level 3 (which will help provide the strategy to “Build Once, Deploy Anywhere”).

Dependency Maturity Model

Level 1 – Env Embedded

This is the first level of an application and it’s reliance on dependencies such as environment properties. In this case, I want to track where the environment specific properties exist (from the source to the build artifact). The problem with this level is that the applications and components have hard-coded properties such as FTP locations, email addresses, and other properties that are required to change per the environment they exist in. And depending on the development shop you work in, you could have multiple environments (such as Development, Integration, Quality Assurance, User Acceptance Testing, Staging, and Production). When the applications/components are littered with environment specific properties/dependencies, it becomes necessary for build management to rebuild the source into the build/deployment artifact for each environment. So the code not only has to be built for each specific environment, the code has to be modified in order to build it for a specific environment. This will require environment specific coding changes, builds, deployments, and potential testing issues based on the changes that are made for that environment. The build artifact is therefore embedded with environment properties and is only deployable to the environment to which it is built for. This would be the equivalent of having APIs in Java (JARs) that have environment properties littered through the claases and then have those JAR files pulled into a WAR file that has some of the same redundant properties within it. So I need to fix the issue of changing the code for each environment by removing the environmental properties out of the code and put that into an external resource (Level 2).

Level 2 – Env Abstract

This is the second level of an application in which I decide to remove the redundant environment properties from the applications/components and put them into an external resource (such as a property file) that all the applications will import and use. This greatly helps development because know I don’t have the potential for redundant and incorrect properties littering the code (maintaining a single source of information for the properties). This also helps the build management somewhat because the code doesn’t have to be modified before each build is done. This would essentially be like removing the environment properties from the APIs in Java (JARs) and the WAR file and putting those properties in a single file (and JAR) that gets pulled into the final WAR. This definitely was a progression from Level 2, the only problem is that I still have not met the “Build Once, Deploy Anywhere” strategy. The reason is that I have successfully pulled the environment specific properties into a single source of truth (property file/JAR), but when I do a build, I are still building an environment specific artifact. So when I combined the Agnostic Code with the Abstract Environment JAR (for Development), I essentially get a Development only WAR. The same can be said when I take that Agnostic Code with the QA Environment JAR, I will get a QA only war from the build. This requires the deployments to only deploy the environment specific artifact (WAR) to that environment, because it cannot work in any other environment. So the next thing I need to do is remove the environment specific resource from the build artifact (Level 3).

Level 3 – Env Abstract

This is the third level of an application in which I now take the final step to realize “Build Once, Deploy Anywhere”. In order to do this, I need to simply not include the environment specific resource into the final application build artifact. This is really as simple as it sounds, when the application/component is brought together into the final artifact (WAR), the environment specific resource (JAR) is not included. This creates a final build artifact that is agnostic to the environment it is deployed to and therefore only needs to be built once and can be deployed to any environment without issue. This is a huge advantage because essentially through the Development Architecture, the Continuous Integration tool can build the application and deploy it to the Maven Repository and then the same Continuous Integration tool can pull that artifact from the Maven Repository and deploy it to any of the environments. This helps insure that the artifact (WAR) that the QA is testing again is the same exact artifact (WAR) that is being deployed int Staging.

Now you maybe thinking that this sounds good and makes sense, but what about the environment properties in Level 3, where did they go. This is where I can utilize capabilities such as OSGi bundles or application server specific capabilities for shared libraries. In WebLogic, this concept can be accomplished through what is called Optional Packages. Essentially what is done is that through the MANIFEST, I define an entry for the environment specific artifact (JAR) that gives an identification and version for that artifact. Then when the agnostic artifact (WAR) is deployed, it also has an entry in it’s MANIFEST for a dependency on the environment specific artifact (JAR) by listing that identification information and version. This way the environment specific artifact (JAR) can be deployed to the container separately from the WAR and at anytime (a new deploy only requires the dependent WARs to be restarted). For local testing, I utilize the capabilities of Maven to define the environment specific artifact as a test so that it can be used for local testing (since it is excluded from the final build artifact). In an additional blog post, I will go deeper into what I had to do to create these Optional Packages and then finally how to create a custom plugin to deploy these artifacts because the maven-weblogic-plugin does not support the deployment of these types of optional jars (ones that are not configured with WebLogic specific config files).

Share and Enjoy