The Holy Java

Building the right thing, building it right, fast

Posts Tagged ‘jboss’

Handling Deployments When Provisioning JBoss domain.xml (With Ansible)

Posted by Jakub Holý on February 24, 2014

It is tricky to manage JBoss with a provisioner such as Puppet or Ansible because its domain.xml contains not only rather static configuration but also sections that change quite often such as deployments. So how can we manage the static parts of domain.xml with f.ex. Ansible while still enabling developers to deploy at will via jboss-cli (and thus changing the <deployments> sections of the file)? Here is one possible solution, based on extracting the sections from the current file and merging them into the template.

Read the rest of this entry »

Posted in General | Tagged: , , | Comments Off

JBoss Modules Suck, It’s Impossible To Use Custom Resteasy/JAX-RS Under JBoss 7

Posted by Jakub Holý on February 4, 2014

Since JBoss EAP 6.1 / AS 7.2.0 is modular and you can exclude what modules are visible to your webapp, you would expect it to be easy to ignore the built-in implementation of JAX-RS (Rest Easy 2.3.6) and use a custom one (3.0.6). However, sadly, this is not the case. You are stuck with what the official guide suggests, i.e. upgrading Rest Easy globally – provided that no other webapp running on the server becomes broken by the upgrade.

Read the rest of this entry »

Posted in j2ee | Tagged: , , | 5 Comments »

Creating Custom Login Modules In JBoss AS 7 (and Earlier)

Posted by Jakub Holý on June 21, 2012

JBoss AS 7 is neat but the documentation is still quite lacking (and error messages not as useful as they could be). This post summarizes how you can create your own JavaEE-compliant login module for authenticating users of your webapp deployed on JBoss AS. A working elementary username-password module provided.

Read the rest of this entry »

Posted in j2ee, Languages, Tools | Tagged: , , , | Comments Off

How I managed to deploy a JSF/Seam portlet to JBoss after all

Posted by Jakub Holý on April 20, 2009

Deploying a custom JSF/Seam portlet to JBoss Portal Server isn’t as easy as you’d expect, either manually or using Eclipse with JBoss Tools. I’ll share with you what I learned about this.

Introduction

See the previous Seam Tutorial 1.1 and 1.2 to learn what SW versions I use, how to configure a server in Eclipse etc. The issues with JBoss Tools, JBoss Portal, and Seam/RichFaces depend pretty much on their respective version and can change significantly even with a minor version change.

Including:

  • jboss-portlet-bridge-1.0.0.B6

In the blog JBoss Portlet support in Eclipse you may learn more about creating portlets for JBoss in Eclipse and issues with various versions of JBoss Tools.

Deploying a portlet via Maven 2

JBoss provides Maven archetypes for creating Seam portlets and also tasks for deploying them to a portal server, either an existing one or a newly downloaded one. This is described in the development guide but not sufficiently.

Note: You need maven 2.0.9 or higher.

  1. run$ mkdir /tmp/jboss; cd /tmp/jboss
  2. run$ mvn archetype:generate
    -DarchetypeGroupId=org.jboss.portletbridge.archetypes
    -DarchetypeArtifactId=seam-basic
    -DarchetypeVersion=1.0.0.B6
    -DgroupId=eu.ibacz.seamtutorial2
    -DartifactId=seamproject
    -DarchetypeRepository=http://repository.jboss.org/maven2/

    (accept all defaults)
  3. cd /tmp/jbossrun/seamproject
  4. edit /tmp/jboss/seamproject/web/pom.xml
    • Running mvn install would fail because of missing org.jboss.portletbridge:portletbridge-api:jar:1.0-SNAPSHOT for  eu.ibacz.seamtutorial2.web:seamproject:war:1.0-SNAPSHOT.
    • => replace <version>${project.version}</version> with <version>${portletbridge.version}</version> for artifactId portletbridge-api in /tmp/jboss/seamproject/web/pom.xml
  5. run$  mvn install
    This will create a WAR package and install it into the local maven repository.
  6. run$ cd /tmp/jboss/seamproject/ear
  7. run$  mvn -Plocal-portal cargo:start
    This uses the Maven plugin cargo to start a local JBoss Portal. It must be run from the ear/ folder because ear/pom.xml defines the necessary settings.
  8. Set the JDK to use if needed – JBoss requires JRE 1.5. and has troubles under 1.6. You may define the JRE to use by adding a property like
    <cargo.java.home>/path/to/jdk1.5.0_17/jre</cargo.java.home>

    to the other cargo properties in ear/pom.xml
    Indication of the problem: an error like below in jboss startup log:
    [INFO] [talledLocalContainer] Caused by: java.lang.UnsupportedOperationException: setProperty must be overridden by all subclasses of SOAPMessage
    – Strangely jboss still reports jre 1.6 after setting this property but the error disappears:
    [INFO] [talledLocalContainer] 10:14:54,415 INFO  [ServerInfo] Java version: 1.6.0_07,Sun Microsystems Inc.

    Output:
    [INFO] [cargo:start]
    [INFO] [talledLocalContainer] Parsed JBoss version = [4.2.3]
    [INFO] [talledLocalContainer] JBoss 4.2.3 starting…

    [INFO] [talledLocalContainer] 10:01:34,211 INFO [Server] JBoss (MX MicroKernel) [4.2.3.GA (build: SVNTag=JBoss_4_2_3_GA date=200807181417)] Started in 2m:34s:75ms

  9. (in new window) run$ mvn cargo:deploy -Plocal-portal
    [INFO] [cargo:deploy]
    [INFO] [talledLocalContainer] Parsed JBoss version = [4.2.3]
    [INFO] [stalledLocalDeployer] Deploying [/POWEROLAP/jboss/seamproject/ear/target/seamproject-1.0-SNAPSHOT.ear] to [/POWEROLAP/jboss/seamproject/ear/target/installs/jboss-portal-2.7.0.GA-bundled/jboss-portal-2.7.0.GA/server/default/deploy]...
    (Some related logs are added also to the window where we started jboss.)
  10. Go to http://localhost:8080/portal You should see a tab called “seamproject” in the portal.

The bug report DOC-13317 describes the shortcomings of the documentation for this.

Manual deployement of a Seam portlet created with Eclipse/JBoss Tools

How to create a Seam portlet in Eclipse with JBoss Tools and deploy it to JBoss Portal.

Create a new Seam portlet project

Note> There are multiple ways to create a Seam Portlet project.

New > Project > Dynamic Web Project >

  1. Page Dynamic Web Project:
    • Target runtime: jboss 4.3.2 portal 2.7.1,
    • Dynamic Web Module version: 2.5
    • Configuration “JBoss Seam Portlet Project v2.0″; if you haven’t it on the selection list, click [Modify…] and select the facets Seam, JBoss Portlets and all under it (JBoss Core Portlet, JBoss JSF Portlet, JBoss Seam Portlet), Java, Dynamic Web Module.
    • Click Next >
  2. Page Web Modules: keep the defaults.
  3. Page JBoss Portlet Capabilities: keep the defaults (Enable implementation library, Libraries provided by server runtime).
  4. Page JSF Capabilities: keep the defaults (Server supplied JSF implementation, …).
  5. Page Seam Facet: set the Seam runtime and Database as we did in the other projects of my Seam/RichFaces tutorials (TODO link).
  6. Page JBoss Portlet Capabilities: Portletbridge Runtime: select e.g. jboss-portal-2.7.1/server/default/deploy/jboss-portal.sar/lib .

Add a portlet to the project

New > Other… > JBoss Tools Web > Portlet > JBoss JSF/Seam Portlet (there is also a plain Java Portlet).

Accept all defaults. This will create a portlet called seamPortlet that will display the page home.xhtrml.

Deploy the portlet

One we have created s Seam portlet we would like to be able to deploy it to JBoss Portal. Here we will learn how to deploy it manually, that means by exporting it from Eclipse as a WAR file and installing that to the server. If you try that you will fail. Below I describe the necessary steps to get the exported WAR working under JBoss.

By comparing the SeamBooking example portlet that you can find in the portlet bridge download package and my Seam portlet exported from Eclipse I’ve discovered the following differences.

  • SeamBooking’s META-INF/ contains a persistence.xml (likely some JPA stuff).
  • SeamBooking’s jboss-portlet.xml defines links to 2 RichFaces JavaScript files and 1 CSS file.
  • SeamBooking’s jboss-object.xml has the property theme.renderSetId=emptyRenderer .
  • My portlet exported from Eclipse contains many libraries in WEB-INF/lib/ but not e.g. any portletbridge stuff.

Deploy the exporeted WAR to JBoss and start it.

Attempt I – failure:

  1. Missing portletbridge class:
    Cause: Unable to find class 'org.jboss.portletbridge.application.PortletViewHandler'

    &l
    t;li>Missing datasource.

Solution:

  1. Copy portletbridge-impl.jar and portletbridge-api.jar to the WAR’s WEB-INF/lib/.
  2. Copy
    /resources/*-ds.xml to deploy/.

Attempt II – failure:

ERROR [LifeCycle] Cannot start objectorg.jboss.portal.portlet.container.PortletInitializationException: The portlet seamPortlet threw a runtime exception during init
Caused by: java.lang.ClassCastException: javax.portlet.faces.GenericFacesPortlet cannot be cast to javax.portlet.Portlet
    at org.jboss.portal.portlet.impl.jsr168.PortletContainerImpl.start(PortletContainerImpl.java:254)

Solution: Remove all portal*, portlet*.jar including portlet-api.jar (contains javax.portlet.Portlet.class), excluding. portletbridge.

Attempt III – portlet running:

No there are no more exceptions and when JBoss Portal starts, you will see there the tab “seamPortlet” with your portlet.

However when you go to the tab to see your portlet there will be another exception:

ERROR [InternalPortletContentProvider] Portlet invoker exception during portlet window renderingorg.jboss.portal.portlet.PortletInvokerException: javax.servlet.ServletException
Caused by: java.lang.NoSuchMethodError: org.ajax4jsf.context.ViewResources.processHeadResources(Ljavax/faces/context/FacesContext;)V

Solution: Replace libs with richfaces-api-3.3.0.GA.jar richfaces-impl-3.3.0.GA.jar richfaces-ui-3.3.0.GA.jar

Attempt VI – everything finally works.

Seam portlet deployment from Eclipse with JBoss Tools

This is something I haven’t managed so far :-(

Posted in Portlets | Tagged: , , , , , , , , , , | 2 Comments »

Redeploy an application (ear/war/…) on JBoss

Posted by Jakub Holý on April 12, 2006

A) Via JMX-console

  1. find jboss.system:service=MainDeployer
  2. invoke listDeployed – find something like:
    org.jboss.deployment.DeploymentInfo@d78e875f { url=file:/C:/jboss-3.2.3/server/default/deploy/tap.ear } 
  3.   copy the url, go back and invoke Redeploy with the url (file:/C:/…) as the parameter.

B) From the command line

The operations that can be invoked via the JBoss JMX console can also be invoked by the cmd line client <jboss home>/bin/twiddle.

C) Manually

Modify application.xml (or web.xml for .war) of the application if deployed in the expload mode (or modify/touch/ the .ear?)

Posted in j2ee | Tagged: , , , | Comments Off

Access EJB on JBoss from outside

Posted by Jakub Holý on April 10, 2006

How to acces an enterprise java bean (EJB) running on JBoss from a standalone application running outside JBoss?

  1. In the code you must, among others:
    1. Set properties for a naming context and create one to be able to look the EJB up
    2. Authenticate by JBoss by means of JAAS
  2. To run the application:
    1. Set the classpath (-cp …): it must contain jbosssx.jar (ClientLoginModule), jboss-common.jar and jnpserver.jar (naming stuff) from <jboss home>/server/default/lib
    2. Create the JAAS configuration file sample_jaas.config containing:
      jboss_jaas { org.jboss.security.ClientLoginModule required; };
      

      If you ever wanted to run the application from JBoss, replace the JAAS config file by the following entry in <JBoss home>/server/default/conf/login-config.ml (application-policy name must be the same name as the one passed to the constructor of a LoginContext):

      <application-policy name = "tap_experiments">
             <authentication>
                <login-module code = "org.jboss.security.ClientLoginModule"  flag = "required"></login-module>
             </authentication>
          </application-policy>
      
    3. Pass the file to the JVM: -Djava.security.auth.login.config=sample_jaas.config
    4. Set a security manager by passing the following options to the JVM:
      -Djava.security.manager -Djava.security.policy="<jboss home>\server\default\conf\server.policy"
import java.rmi.RemoteException;
import java.util.Properties;

import javax.ejb.CreateException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import com.teradata.tap.system.query.ejb.QueryEngineRemote;
import com.teradata.tap.system.query.ejb.QueryEngineRemoteHome;

/**
 * Call a business method of an EJB running on JBoss
 */
public class ExternalCallEjbSample {

        public static void main(String[] args) {
                // 1: Get the naming Context
                // Required JARs (in jboss/server/default/lib): jboss-common.jar, jnpserver.jar 
                Properties props = new Properties();
                //      Matches the java.naming.factory.initial property in jndi.properties
                props.put(Context.INITIAL_CONTEXT_FACTORY,
                                "org.jnp.interfaces.NamingContextFactory");
                //      Matches the java.naming.provider.url property in jndi.properties
                props.put(Context.PROVIDER_URL, "jnp://localhost:1099");
                props.put(Context.URL_PKG_PREFIXES,
                                "org.jboss.naming:org.jnp.interfaces");
                QueryEngineRemoteHome queryEngineHome = null;

                try {

                        Context ctx = new InitialContext(props);

                        /*/ Print all entries in the JNDI
                         NamingEnumeration ne = ctx.list("java:");
                         while (ne.hasMore()) {
                         System.out.println("A: " + ne.next().toString());
                         } //*/

                        // Look up and instantiate the home interface of the EJB
                        // IMPORTANT: It fails if no SecurityManager specified for RMI class loader will be disabled
                        // -> add these options to the JVM:
                        // -Djava.security.manager -Djava.security.policy=" home>\server\default\conf\server.policy"
                        String beanName = QueryEngineRemoteHome.JNDI_NAME;
                        System.out.println("Looking up '" + beanName + "'");
                        Object lookup = ctx.lookup(beanName);

                        queryEngineHome = (QueryEngineRemoteHome) PortableRemoteObject
                                        .narrow(lookup, QueryEngineRemoteHome.class);

                } catch (NamingException e) {
                        System.out.println("new InitialContext failed:" + e);
                }

                // 2. Instantiate the (remote) EJB and call its business method(s)
                // 2.1 I have to authenticate unless security allows anybody to call create on the EJB
                //      Otherwise an EJBException: checkSecurityAssociation will be thrown.
                // TODO: JVM option -Djava.security.auth.login.config==sample_jaas.config - use org.jboss.security.ClientLoginModule
                // and have  home>\server\default\lib\jbosssx.jar on the path (class ClientLoginModule)
                // Listing of sample_jaas.config:
                //      jboss_jaas { org.jboss.security.ClientLoginModule required debug=true; };
                LoginContext loginContext = null;
                boolean loggedIn = false;
                try {
                        CallbackHandler handler = new MyPresetCallbackHandler("tapdev","tapdev");
                        // jboss_jaas - name of a configuration in the jaas config file 
                        loginContext = new LoginContext("jboss_jaas", handler);
                        System.out.println("Created LoginContext");
                        loginContext.login(); // throws LoginException
                        System.out.println("Logged in.");
                        loggedIn = true;
                } catch (LoginException le) {
                        System.out.println("Login failed");
                        le.printStackTrace();
                }

                // Create & use the EJB:
                if (loggedIn && queryEngineHome != null) {
                        try {
                                QueryEngineRemote queryEngine = queryEngineHome.create();
                                System.out.println("queryEngine remote created.");
                                // TODO: call business method(s)
                        } catch (RemoteException e1) {
                                e1.printStackTrace();
                        } catch (CreateException e1) {
                                e1.printStackTrace();
                        }
                }

                // Log out
                if (loggedIn && loginContext != null) {
                        try {
                                loginContext.logout();
                        } catch (LoginException e) {
                                System.out.println("Logout failed:" + e);
                        }
                }

                System.out.println("## DONE! ##");
        } // main

        /** Authentication CallbackHandler with preset username/password. */
        static class MyPresetCallbackHandler implements CallbackHandler {
                String username;

                char[] password;

                public MyPresetCallbackHandler(String username, String password) {
                        this.username = username;
                        this.password = password.toCharArray();
                }

                public void handle(Callback[] callbacks) throws java.io.IOException,
                                UnsupportedCallbackException {
                        for (int i = 0; i < callbacks.length; i++) {
                                Callback callback = callbacks[i];
                                if (callback instanceof NameCallback) {
                                        ((NameCallback) callback).setName(username);
                                } else if (callback instanceof PasswordCallback) {
                                        ((PasswordCallback) callback).setPassword(password);
                                } else {
                                        throw new UnsupportedCallbackException(callback,
                                                        "Unrecognized Callback");
                                }
                        }
                }// handle 
        }// MyPresetCallbackHandler
}

See EjbLocator.java
and EjbLocatorException.java.
With them, you can replace all above with QueryEngineRemote queryEngine = (QueryEngineRemote) EjbLocator.getInstance().locate( QueryEngineRemoteHome.JNDI_NAME );

Posted in j2ee | Tagged: , , , | Comments Off