Apache Tapestry: Absolute path to assets in META-INF/assets - java

The solution here helps me get absolute path to assets in class-path (context)
Tapestry 5 - Dynamically generate URL of file in web app context folder in Java code
Is there a way to do the same for assets stored in META-INF/assets (Tapestry 5.4 way of storing assets)?
Specifically, I'd like to inject the path of the a .html (static) file I've created in META-INF/assets folder..
at the moment I have:
public String getMyHtml() {
String clientURL = assetSource.getContextAsset("html/myhtml.html", locale).toClientURL();
return clientURL;
}
and the tml file has:
"{ url: '${getDeltaHtml()}' }"
This works if "myhtml.html" file is located in class path folder (WEB-INF). It does not work if its in META-INF/assets folder, which is where I'd like to put it

You can get hold of the assets stored under assets by this.
First you have to inject the following.
#Inject
private AssetSource assetSource;
#Inject
private ThreadLocale threadLocale;
After that you can use the following to get the Assets.
Asset asset = assetSource.getAsset(null, "classpath:META-INF/assets/myhtml.html", threadLocale.getLocale());

Related

Save file with relative path from javabean or servlet

I need to save file from javabean or servlet, and I'm having trouble finding relative path, I tried:
(from servlet)
ServletContext servCont = this.getServletContext();
String contextPath = servCont.getRealPath(File.separator);
System.out.println("REAL PATH: "+ contextPath);
this gives me:
REAL PATH: E:\Web\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\Saloni\
and project folder is:
E:\Web\Saloni
and from bean (bean is called Salon)
String path = Salon.class.getResource("Salon.class").getPath();
and got basically the same thing
/E:/Web/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Saloni/WEB-INF/classes/beans/Salon.class
If I just put file name into FileOutputStream file gets saved in eclipse workspace.
I read somewhere that I'm supposed to get to WEB-INF somehow but can't do that ..

Understanding MultipartFile transferTo() method in Spring MVC

I am using Spring Framework's MultipartFile to allow a user to upload a picture to a profile. I've configured DispatcherServlet in a servlet initializer class that extends AbstractAnnotationConfigDispatcherServletInitializer. In that class, I've overridden the customizeRegistration() method as follows:
#Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(new MultipartConfigElement("/tmp/practicewellness/uploads", 2097152, 4194304, 0));
}
The MultipartFile's transferTo() method calls for a file location in the filesystem where the uploaded file will be written temporarily. Can this location be anywhere? When I used the following location in the method:
profilePicture.transferTo(new File("tmp/practicewellness/" + employee.getUsername() + ".jpg"));
... I get the following error:
Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [C:\Users\kyle\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp2\work\Catalina\localhost\practicewellness\tmp\practicewellness\uploads] is not valid
So I can see that it's looking for this file location deep inside one of my Eclipse plugins. I don't understand why it looks there. When I look there, the "tmp" directory is not there. But regardless, is it okay for me to go into that plugin and create the directory there? Or is there a better way to smooth this out?
I've uploaded files using Spring mvc, but never used transferTo(), I just assume that your problem is due to "No existence of specified path" because there wont be a path ending with .jpg. Try it like this.
String path = "/tmp/practicewellness/";
File dirPath = new File(path);
if (!dirPath.exists()) {
dirPath.mkdirs();
}
And then execute the transferTo() code.
Also do not set the path directly like you've done. Since you're doing it in spring, so I assume you want the folder to be in your Project path not the eclipse's metadata path. So change your path to this.
String path = request.getSession().getServletContext().getRealPath("/tmp/practicewellness/");
It will create a folder inside your Project's Webapp folder using mkdir. If you want to save differentiate the files for each user, you can create a folder for each user by using this below path.
String path = request.getSession().getServletContext().getRealPath("/tmp/practicewellness")+"/"+employee.getUsername()+"/";

How to get list of files in some folder of my war file?

I have a Java project (Spring). I need to get list of images from folder "images" and randomly choose one of them. I have a problem with getting list of files from a this directory in my war file. What class can I use for it? And how I can set a path to my folder?
Thank you for your help help!
P.S. I use a service (not Controller) which should give me a name of random image from my images folder? It looks like:
<body style="background: url(request.getContextPath() + RandomBackgroundService.getRandomBackground()) ...
How my Service will look?
You can get the list from ServletContext.getResourcePaths() - just autowire a reference into your controller and ask for the correct folder-
#Controller
#RequestMapping("/whatever")
public class MyClass {
#Autowired
private final ServletContext context;
#RequestMapping(method = RequestMethod.GET)
public String get(ModelMap model) {
Random rand = new Random();
List<String> images = new ArrayList<String>(context.getResourcePaths("/images"));
model.addAttribute("randomImage", images.get(rand.nextInt(images.size())));
return "myPage";
}
}
To begin with, ignore the "target" directory. It is just where maven places the results of it's processing.
If you need to retrieve data from a WAR file directory in runtime, I would use something like:
for (String s : req.getServletContext().getResourcePaths("images")) {
InputStream resource = req.getServletContext.getResourceAsStream(s);
// do something with resource
}
If you are trying to access the images directory from a class this should work:
File imagesFolder = MyClass.getResource("images").getFile();
for (File image : imagesFolder.listFiles()) {
// TODO: Figure out your random logic.
}
Reading the documentation on Class.getResource() may also help you when determine how to access resources within an application.

How to get absolute path to file in /resources folder of your project

Assume standard maven setup.
Say in your resources folder you have a file abc.
In Java, how can I get absolute path to the file please?
The proper way that actually works:
URL resource = YourClass.class.getResource("abc");
Paths.get(resource.toURI()).toFile();
It doesn't matter now where the file in the classpath physically is, it will be found as long as the resource is actually a file and not a JAR entry.
(The seemingly obvious new File(resource.getPath()) doesn't work for all paths! The path is still URL-encoded!)
You can use ClassLoader.getResource method to get the correct resource.
URL res = getClass().getClassLoader().getResource("abc.txt");
File file = Paths.get(res.toURI()).toFile();
String absolutePath = file.getAbsolutePath();
OR
Although this may not work all the time, a simpler solution -
You can create a File object and use getAbsolutePath method:
File file = new File("resources/abc.txt");
String absolutePath = file.getAbsolutePath();
You need to specifie path started from /
URL resource = YourClass.class.getResource("/abc");
Paths.get(resource.toURI()).toFile();
Create the classLoader instance of the class you need, then you can access the files or resources easily.
now you access path using getPath() method of that class.
ClassLoader classLoader = getClass().getClassLoader();
String path = classLoader.getResource("chromedriver.exe").getPath();
System.out.println(path);
There are two problems on our way to the absolute path:
The placement found will be not where the source files lie, but
where the class is saved. And the resource folder almost surely will lie somewhere in
the source folder of the project.
The same functions for retrieving the resource work differently if the class runs in a plugin or in a package directly in the workspace.
The following code will give us all useful paths:
URL localPackage = this.getClass().getResource("");
URL urlLoader = YourClassName.class.getProtectionDomain().getCodeSource().getLocation();
String localDir = localPackage.getPath();
String loaderDir = urlLoader.getPath();
System.out.printf("loaderDir = %s\n localDir = %s\n", loaderDir, localDir);
Here both functions that can be used for localization of the resource folder are researched. As for class, it can be got in either way, statically or dynamically.
If the project is not in the plugin, the code if run in JUnit, will print:
loaderDir = /C:.../ws/source.dir/target/test-classes/
localDir = /C:.../ws/source.dir/target/test-classes/package/
So, to get to src/rest/resources we should go up and down the file tree. Both methods can be used. Notice, we can't use getResource(resourceFolderName), for that folder is not in the target folder. Nobody puts resources in the created folders, I hope.
If the class is in the package that is in the plugin, the output of the same test will be:
loaderDir = /C:.../ws/plugin/bin/
localDir = /C:.../ws/plugin/bin/package/
So, again we should go up and down the folder tree.
The most interesting is the case when the package is launched in the plugin. As JUnit plugin test, for our example. The output is:
loaderDir = /C:.../ws/plugin/
localDir = /package/
Here we can get the absolute path only combining the results of both functions. And it is not enough. Between them we should put the local path of the place where the classes packages are, relatively to the plugin folder. Probably, you will have to insert something as src or src/test/resource here.
You can insert the code into yours and see the paths that you have.
To return a file or filepath
URL resource = YourClass.class.getResource("abc");
File file = Paths.get(resource.toURI()).toFile(); // return a file
String filepath = Paths.get(resource.toURI()).toFile().getAbsolutePath(); // return file path

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

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?
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:
the web module document root - resources are accessible from the browser and from classes
WEB-INF/classes/ - resources are accessible to classes
WEB-INF/lib/*.jar source jar - accessible to classes
WEB-INF/lib/*.jar dedicated resource-only jar - accessible to classes
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)
The way to access files under WEB-INF is via three methods of ServletContext:
getResource("/WEB-INF/testdata.xml") gives you a URL
getResourceAsStream gives you an input stream
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.
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
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";

Categories