How do I reference a file that is placed in the WEB-INF folder when using Arquillian?
Asked Answered
A

4

7

I am using maven and the standard directory layout. So I have added a testdata.xml file in the src/test/resources folder, and I also added it as:

.addAsWebInfResource("testdata.xml", "testdata.xml")

in the deployment method, and I have confirmed that it is there. This will make the file appear in /WEB-INF/testdata.xml. Now I need to have a reference to this file in my code and I tried several different getClass().getResourceAsStream(...) and failing again and again so I need some advise now.

I need it for my DBUnit integration test. Is this not possible?

Abby answered 28/10, 2012 at 20:54 Comment(3)
It should be in the classpath to do Class.getResourseAsStream(). Not everything inside WEB-INF are put in the classpath. Only the contents of the classes folder in WEB-INF is are added to the classpath. You can get the path of the context path and append to it the rest of the location.Mcbee
Or if you have access to ServletContext the you can do servletContext.getRealPath("/WEB-INF/testdata.xml").Mcbee
@Dude, is this XML file a DbUnit flat XML file containing data to be used in the tests?Jeanelle
W
19

Option A) Use ServletContext.getResourceXXX()

You should have a Aquillarian MockHttpSession and a MockServletContext. E.g.:

@Test
   public void myTest()
   {
      HttpSession session = new MockHttpSession(new MockServletContext());
      ServletLifecycle.beginSession(session);

      ..testCode..

      // You can obtain a ServletContext (will actually be a MockServletContext 
      // implementation):
      ServletContext sc = session.getServletContext();
      URL url = sc.getResource("/WEB-INF/testdata.xml")
      Path resPath = new Path(url);
      File resFile = new File(url);
      FileReader resRdr = new FileReader(resFile);
      etc...

      ..testCode..

      ServletLifecycle.endSession(session);
   }

You can create resource files & subdirectories in:

  1. the web module document root - resources are accessible from the browser and from classes
  2. WEB-INF/classes/ - resources are accessible to classes
  3. WEB-INF/lib/*.jar source jar - accessible to classes
  4. WEB-INF/lib/*.jar dedicated resource-only jar - accessible to classes
  5. WEB-INF/ directly within directory - accessible to classes. This is what you are asking for.

In all cases the resource can be accessed via:

URL url = sc.getResource("/<path from web doc root>/<resourceFileName>");
OR    
InputStream resIS = sc.getResourceAsStream("/<path from web doc root>/<resourceFileName>");

>

These will be packaged into the WAR file and may be exploded into directories on the deployed app server OR they may stay within the WAR file on the app server. Either way - same behaviour for accessing resources: use ServletContext.getResourceXXX().

Note that as a general principle, (5) the top-level WEB-INF directory itself is intended for use by the server. It is 'polite' not to put your web resources directly in here or create your own directory directly in here. Instead, better to use (2) above.

JEE5 tutorial web modules JEE6 tutorial web modules

Option B): Use Class.getResourceXXX()

First move the resource out of WEB-INF folder into WEB-INF/classes (or inside a jar WEB-INF/lib/*.jar).

If your test class is:

  • com.abc.pkg.test.MyTest in file WEB-INF/classes/com/abc/pkg/test/MyTest.class

And your resource file is

  • WEB-INF/classes/com/abc/pkg/test/resources/testdata.xml (or equivalent in a jar file)

Access File using Relative File Location, via the Java ClassLoader - finds Folders/Jars relative to Classpath:

java.net.URL resFileURL = MyTest.class.getResource("resources/testdata.xml");
File resFile = new File(fileURL);    
OR
InputStream resFileIS = 
     MyTedy.class.getResourceAsStream("resources/testdata.xml");

Access File Using full Package-like Qualification, Using the Java ClassLoader - finds Folders/Jars relative to Classpath:

java.net.URL resFileURL = MyTest.class.getResource("/com/abc/pkg/test/resources/testdata.xml");
File resFile = new File(fileURL);        
OR 
InputStream resFileIS = 
     MyTest.class.getResourceAsStream("/com/abc/pkg/test/resources/testdata.xml");   
OR 
java.net.URL resFileURL = MyTest.class.getClassLoader().getResource("com/abc/pkg/test/resources/testdata.xml");
File resFile = new File(fileURL);       
OR 
InputStream resFileIS = 
     MyTest.class.getClassLoader().getResourceAsStream("com/abc/pkg/test/resources/testdata.xml");

Hope that nails it! @B)

Weingartner answered 5/11, 2012 at 5:34 Comment(4)
java.io.File doesn't have a constructor for java.net.URL therefore your File resFile = new File(url); conversions won't even compileLepto
As @Lepto states, java.io.File does not have a java.net.URL constructor.Oversize
File has had a constructor File(URI) since Java 1.4. URL extends URI.Skewness
Oops. URL actually doesn't extend URI, and URL.toURI() declares a checked Exception. How annoying.Skewness
A
5

The way to access files under WEB-INF is via three methods of ServletContext:

  1. getResource("/WEB-INF/testdata.xml") gives you a URL
  2. getResourceAsStream gives you an input stream
  3. getRealPath gives you the path on disk of the relevant file.

The first two should always work, the third may fail if there is no direct correspondence between resource paths and files on disk, for example if your web application is being run directly from a WAR file rather than an unpacked directory structure.

Aftmost answered 2/11, 2012 at 21:5 Comment(1)
How do I get a servlet context object when I use Arquillian?Abby
L
2

Today I was struggling with the same requirement and haven't found any full source sample, so here I go with smallest self contained test I could put together:

@RunWith(Arquillian.class)
public class AttachResourceTest {

    @Deployment
    public static WebArchive createDeployment() {
        WebArchive archive =  ShrinkWrap.create(WebArchive.class).addPackages(true, "org.apache.commons.io")
                .addAsWebInfResource("hello-kitty.png", "classes/hello-kitty.png");             
        System.out.println(archive.toString(true));
        return archive;
    }

    @Test
    public void attachCatTest() {
        InputStream stream = getClass().getResourceAsStream("/hello-kitty.png");
        byte[] bytes = null;
        try {
            bytes = IOUtils.toByteArray(stream);
        } catch (IOException e) {
            e.printStackTrace();
        }   
        Assert.assertNotNull(bytes);
    }
}

In your project hello-kitty.png file goes to src/test/resources. In the test archive it is packed into the /WEB-INF/classes folder which is on classpath and therefore you can load it with the same class loader the container used for your test scenario.

IOUtils is from apache commons-io.

Additional Note: One thing that got me to scratch my head was related to spaces in path to my server and the way getResourceAsStream() escapes such special characters: sysLoader.getResource() problem in java

Lepto answered 10/9, 2014 at 16:12 Comment(1)
Why not use Java 7 File API?Rucksack
A
1

Add this class to your project:

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

public class Init {
    private static final String WEB_INF_DIR_NAME="WEB-INF";
    private static String web_inf_path;
    public static String getWebInfPath() throws UnsupportedEncodingException {
        if (web_inf_path == null) {
            web_inf_path = URLDecoder.decode(Init.class.getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF8");
            web_inf_path=web_inf_path.substring(0,web_inf_path.lastIndexOf(WEB_INF_DIR_NAME)+WEB_INF_DIR_NAME.length());
        }
        return web_inf_path;
    }
}

Now wherever you want to get the full path of the file "testdata.xml" use this or similar code:

String testdata_file_location = Init.getWebInfPath() + "/testdata.xml";
Asphyxiate answered 6/11, 2012 at 6:57 Comment(3)
HI Abhishek : I tried ur code..I kept the .properties file inside WEB-INF.. when i print the testdata_file_location it is printing like E:\ec\temp.properties ..So i dont know why it is doing.So how to read properties from itTheft
@Theft are you running your project using some IDE? and can u also tell us the version of Tomcat or Glassfish or whatever you are using? looks like the ec.war has been deployed in E: drive, and/or the docBase property in <tomcat_folder>/conf/catalina/localhost/ec.xml's Context element is pointing to such location. Also check if you are using web_inf_path.lastIndexOf(WEB_INF_DIR_NAME)+WEB_INF_DIR_NAME.length() or web_inf_path.lastIndexOf(WEB_INF_DIR_NAME) from the code above (i.e. have u accidently left +WEB_INF_DIR_NAME.length() part of that code?)Asphyxiate
Hi Abhishek i got working..below is my code prop.load(new FileInputStream("./WEB-INF/temp.properties"));Theft

© 2022 - 2024 — McMap. All rights reserved.