2 Replies Latest reply on Feb 27, 2009 1:29 AM by Riccardo Serafin

    Suggestion: Embedded Jboss, Seam Test and duplicate deployment

    Riccardo Serafin Newbie

      Hello,


      as I've been wasting some time with it, I thought it could be useful to share my findings. I was using SeamTest and Embedded jboss for my tests and I noticed that all my ejbs and my persistence units were deployed twice on embedded jboss. In the end no harm resulted, apart a waste of time, but I've decided to investigate anyway the matter.


      The problem is the class EmbeddedBootstrap that setups the embedded jboss deploying all base paths found in the class path that contains a seam.properties, a META-INF/components.xml or a META-INF/seam.properties. If, like me, you both have a seam.properties and a META-INF/components.xml in your classpath (which I thought to be mandatory, but this is another matter...) the EmbeddedBootstrap class will issue a deploy twice for the directory (or jar) containing those files, resulting in a deploy, undeploy, redeploy for that directory (or jar).


      To solve the problem, I guess you could try to remove seam.properties (assuming you need the components.xml to setup stuff) or, as I did, override the startJbossEmbeddedIfNecessary method in AbstractSeamTest and redefine what really needs to be deployed.


      I have created my own solution, which ensures that each resource is deployed only once. If anyone is interested I can post it.


      Cheers,
      Riccardo.

        • 2. Re: Suggestion: Embedded Jboss, Seam Test and duplicate deployment
          Riccardo Serafin Newbie

          Hi,


          here it is. In a class extending the AbstractSeamTest:


              /*
               * (non-Javadoc)
               * @see org.jboss.seam.mock.AbstractSeamTest#startJbossEmbeddedIfNecessary()
               */
              @Override
              protected void startJbossEmbeddedIfNecessary() throws Exception {
                  if (!embeddedStarted && embeddedJBossAvailable()) {
                      new TSBEmbeddedBootstrap().startAndDeployResources();
                  }
                  embeddedStarted = true;
              }
          



          Then the override of the EmbeddedBootstrap:


          /**
           * Overrides the default seam embedded jboss bootstrap process, to customize it
           * for tsb project layouts.
           * 
           * @author rserafin
           * @version $Rev: 994 $ $Date: 2009-01-28 23:26:16 +0100 (Wed, 28 Jan 2009) $
           */
          public class TSBEmbeddedBootstrap extends EmbeddedBootstrap {
          
          
              final LogProvider log = Logging.getLogProvider(TSBEmbeddedBootstrap.class);
          
          
              /**
               * Starts up jboss embedded and configures the deployment.
               */
              @Override
              public void startAndDeployResources() throws Exception {
                  final Bootstrap bootstrap = Bootstrap.getInstance();
          
                  if (!bootstrap.isStarted()) {
                      log.trace("Starting embedded jboss...");
                      bootstrap.setLoader(Thread.currentThread().getContextClassLoader());
                      bootstrap.bootstrap();
          
                      for (final URL url : getResourceBases(Arrays.asList(Configuration.instance()
                          .getEmbeddedBootstrapConfiguration().getDeployersPatterns()))) {
                          log.trace("Deploying: " + url);
                          bootstrap.deploy(url);
                      }
                  }
          
              }
          
          
              /**
               * Gets the actual base resource to be deployed given a resource matching
               * one of the patterns.
               * 
               * @param url complete url
               * @param baseResource pattern used to fine the resource
               * @return url - baseResource
               */
              protected URL getBaseUrl(final URL url, final String baseResource) {
                  String urlString = url.toString();
                  final int idx = urlString.lastIndexOf(baseResource);
                  urlString = urlString.substring(0, idx);
                  URL deployUrl = null;
                  try {
                      deployUrl = new URL(urlString);
                  } catch (final MalformedURLException e) {
                      throw new RuntimeException(e);
                  }
          
                  return deployUrl;
              }
          
          
              /**
               * Scans the class path for the given set of path and adds all related
               * resources to the returned set, in order to be deployed. This ensure that
               * a specific resource is only deployed once, even if it would match more
               * than once of the pattern paths given.
               * 
               * @param paths pattern paths to check.
               * @return a set of unique resources to be deployed.
               * @throws Exception if anything goes wrong.
               */
              protected List<URL> getResourceBases(final Collection<String> paths) throws Exception {
                  final Set<URL> bases = new HashSet<URL>();
                  final List<URL> orderedBases = new ArrayList<URL>();
          
                  for (final String path : paths) {
                      for (final URL url : Collections.list(Thread.currentThread().getContextClassLoader().getResources(path))) {
                          log.trace("Scanning: " + url);
                          final URL baseUrl = getBaseUrl(url, path);
                          if (!bases.contains(baseUrl)) {
                              bases.add(baseUrl);
                              orderedBases.add(baseUrl);
                          }
                      }
                  }
          
                  for (final URL url : orderedBases) {
                      log.trace("Final set: " + url);
                  }
          
                  return orderedBases;
              }
          
          }
          



          where the DeployersPatterns read from my configuration object are something like:


          public final static String[] PATTERNS                    = new String[] { "hsqldb-ds.xml", "seam.properties", "components.properties", "META-INF/components.xml",
                      "META-INF/seam.properties",                     };
          



          Hope this helps.


          Best,
          Riccardo.