What I am trying to accomplish is for some image references in a css file to be located in a folder seperate to the actual application.
Is it possible to mount an external folder as a resource in Wicket?
In pseudocode this is what I am trying to do:
public class Application extends WicketApplication
{
init()
{
mountResource(new FolderResource("Path/to/some/folder", "someid"));
}
}
So that the .css class would reference the resources like this:
.someclass
{
url("resources/someid/images/image.png")
}
I'm sure I've seen this somewhere but I just can't seem to be able to find it again...
EDIT
Should also note that im currently running on Wicket 1.4
As simple as following.
MyApplication.java:
public class MyApplication extends WebApplication {
...
public void init() {
...
final String resourceId = "images";
getSharedResources().add(resourceId, new FolderResource(new File(getServletContext().getRealPath("img"))));
mountSharedResource("/image", Application.class.getName() + "/" + resourceId);
}
...
}
FolderResource.java:
public class FolderResource extends WebResource {
private File folder;
public FolderResource(File folder) {
this.folder = folder;
}
#Override
public IResourceStream getResourceStream() {
String fileName = getParameters().getString("file");
File file = new File(folder, fileName);
return new FileResourceStream(file);
}
}
And then you can get any image from "img" folder inside your application by simple URL:
/your-application/app/image?file=any-image.png
Here "/your-application" is the application context path, "/app" is the Wicket servlet mapping in web.xml, and "any-image.png" is the name of the image file.
Related
I am using Grizzly to serve my REST service which can have multiple "modules". I'd like to be able to use the same base URL for the service and for static content so I can access all these urls:
http://host:port/index.html
http://host:port/module1/index.html
http://host:port/module1/resource
http://host:port/module2/index.html
http://host:port/module2/resource
The code I'm trying to set this up with looks like this:
private HttpServer createServer(String host, int port, ResourceConfig config)
{
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create("http://" + host + ":" + port + "/"), config, false);
HttpHandler httpHandler = new CLStaticHttpHandler(HttpServer.class.getClassLoader(), "docs/");
server.getServerConfiguration().addHttpHandler(httpHandler, "/");
return server;
}
With this code, I am only able to see the html pages and I get a "Resource identified by path does not exist" response when I try to get my resources.
When I comment out the code to add the HttpHandler, then I am able to access my resources (but don't have the docs of course).
What do I need to do to access both my resources and my static content?
I ended up writing a service to handle static resources myself. I decided to serve my files from the file system, but this approach would also work for serving them from a jar - you'd just have to get the file as a resource instead of creating the File directly.
#Path("/")
public class StaticService
{
#GET
#Path("/{docPath:.*}.{ext}")
public Response getHtml(#PathParam("docPath") String docPath, #PathParam("ext") String ext, #HeaderParam("accept") String accept)
{
File file = new File(cleanDocPath(docPath) + "." + ext);
return Response.ok(file).build();
}
#GET
#Path("{docPath:.*}")
public Response getFolder(#PathParam("docPath") String docPath)
{
File file = null;
if ("".equals(docPath) || "/".equals(docPath))
{
file = new File("index.html");
}
else
{
file = new File(cleanDocPath(docPath) + "/index.html");
}
return Response.ok(file).build();
}
private String cleanDocPath(String docPath)
{
if (docPath.startsWith("/"))
{
return docPath.substring(1);
}
else
{
return docPath;
}
}
}
One thing you can do is run Grizzly as a servlet container. That way you can run Jersey as servlet filter, and add a default servlet to handle the static content. For example
public class Main {
public static HttpServer createServer() {
WebappContext context = new WebappContext("GrizzlyContext", "");
createJerseyFilter(context);
createDefaultServlet(context);
HttpServer server = GrizzlyHttpServerFactory
.createHttpServer(URI.create("http://localhost:8080/"));
context.deploy(server);
return server;
}
private static void createJerseyFilter(WebappContext context) {
ResourceConfig rc = new ResourceConfig().packages("com.grizzly.test");
// This causes Jersey to forward 404s to default servlet
// which will catch all the static content requests.
rc.property(ServletProperties.FILTER_FORWARD_ON_404, true);
FilterRegistration reg = context.addFilter("JerseyApp", new ServletContainer(rc));
reg.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), "/*");
}
private static void createDefaultServlet(WebappContext context) {
ArraySet<File> baseDir = new ArraySet<>(File.class);
baseDir.add(new File("."));
ServletRegistration defaultServletReg
= context.addServlet("DefaultServlet", new DefaultServlet(baseDir) {});
defaultServletReg.addMapping("/*");
}
public static void main(String[] args) throws IOException {
HttpServer server = createServer();
System.in.read();
server.stop();
}
}
You will need to add the Jersey Grizzly servlet dependency
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-servlet</artifactId>
<version>${jersey2.version}</version>
</dependency>
The only problem with this approach is that the default servlet is meant to serve files from the file system, not from the classpath, as you are currently trying to do. You can see in the createDefaultServlet method I just set the base directory to the current working directory. So that's where all your files would need to be. You can change it to "docs" so all your files would be in the docs folder, which would be in the current working directory.
If you want to read files from the classpath, you may need to implement your own servlet. You can look at the source code for DefaultServlet and try to modify it to serve from the classpath. You can also check out Dropwizard's AssetServlet, which already does serve content from the classpath.
Or you can just say forget it, and just serve from the file system :-)
I'm trying to achieve a way to obtain the base path of the current classloader when runnning from within a jar.
I mean programatically, I already know it should have the shape of "jarPath+jarFile.jar!/"
Unlike file system's call, getResource(".") or .getResource("/") do not work from inside the jar.
Ideally it should be an abstract solution for any file provider, so something like:
Path BASE_PATH = Paths.get(...getResource("").toURI())
which could return the correct root path for both jars and file system so I can use relative urls to my resources without having to do any conditional statements and url manual string parsing/build.
You should be able to find out the path of the jar and or target folder containing you class or any resource by using this code:
package com.stackoverflow.test;
import java.net.URL;
import java.nio.file.Paths;
public class ClassPathUtils {
public static String getBasePath(String jarPath) {
String path = getJarPathFromClass(jarPath);
if (path == null) {
return null;
}
if (path.startsWith("jar:")) {
path = path.substring("jar:".length());
}
if (path.startsWith("file:")) {
path = path.substring("file:".length());
}
if (path.endsWith(jarPath)) {
path = path.substring(0, path.length()-jarPath.length());
}
return path;
}
public static String getBasePath(Class clazz) {
return getBasePath(classNameDotClass(clazz));
}
private static String classNameDotClass(Class clazz) {
return clazz.getName().replaceAll("\\.", "/") + ".class";
}
private static String getJarPathFromClass(String resource) {
final URL url = ClassPathUtils.class.getClassLoader().getResource(resource);
return url == null ? null : url.toString();
}
public static void main(String[] args) {
//System.out.println(Paths.get(ClassPathUtils.getBasePath("."))); // doesn't work in a jar
System.out.println(Paths.get(ClassPathUtils.getBasePath(ClassPathUtils.class)));
System.out.println(Paths.get(ClassPathUtils.getBasePath("fonts/atcitadelscript.ttf"))); // any classpath resource
System.out.println(Paths.get(ClassPathUtils.getBasePath(String.class))); // actually finds rt.jar
}
}
If you run this code from your IDE, or from maven, it will give you the paths to target/classes for your own resources, or the path to a jar for other resources (E.g. String.class).
If you call it from a jar, it will always tell you the path of the jar file.
run from IDE:
/home/alexander/projects/stackoverflow/stuff/target/classes
/home/alexander/projects/stackoverflow/stuff/target/classes
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar!`
run from JAR:
/home/alexander/projects/stackoverflow/stuff/target/test-stuff-0.1-SNAPSHOT.jar!
/home/alexander/projects/stackoverflow/stuff/target/test-stuff-0.1-SNAPSHOT.jar!
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar!
Is that what you're looking for?
I have JSP projects that run in Tomcat developed in Eclipse.
I want to have some files which I store inside the project.
Here is the project structure that I have:
.settings
build
data
ImportedClasses
src
WebContent
.classpath
.project
I want to access the data folder from my code in JSP file which located in WebContent.
Tried some code below:
File userDataDirFile = new File ( "data" );
String path = userDataDirFile.getAbsolutePath();
prints
C:\Program Files\eclipse\data\users
Then
this.getClass().getClassLoader().getResource("").getPath()
prints
C:/Workspaces/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/survey/WEB-INF/classes/
Another one:
System.getProperty("user.dir")
prints
C:\Program Files\eclipse
There is no code that I tried (I think the 2nd solution supposed to work, but it doesn't) can locate me to root folder of my project. Anyone can advise?
String caminhoProjeto = Thread.currentThread().getContextClassLoader().getResource("").getPath();
This is like "src" path, but is the "classes" path of binaries files context after deployment and runtime.
My class for example of the necessarie use of this way "root dir of project":
PropertiesReader.java:
public class PropertiesReader {
public static String projectPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
public static String propertiesPath = "/META-INF/";
public static Properties loadProperties(String propertiesFileName) throws IOException {
Properties p = new Properties();
p.load(new FileInputStream(projectPath + propertiesPath + propertiesFileName));
return p;
}
public static String getText(String propertiesFileName, String propertie) {
try {
return loadProperties(propertiesFileName).getProperty(propertie);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return propertie;
}
}
PersonRegistration.java:
#ManagedBean
public class PersonRegistration {
private Integer majority = Integer.parseInt(PropertiesLeitor.getText("Brasil.properties", "pessoa.maioridade"));
}
Brasil.properties (within src / META-INF):
pessoa.maioridade = 18
Edit : File that are not in WebContent will not be deployed with your war. you have to put files used in you code inside the WebContent and try with ServletContext which point to the root folder of the your web application :
if your file is at the same folder as WEB-INF then :
ServletContext context = getContext();
String fullPath = context.getRealPath("/data");
by the way if you don't want to give direct access to data file it's recommanded to put it in WEB-INF so that no one can have access to them directly.
I am using the following method to get a resource from WAR file in WildFly:
this.getClass().getResource(relativePath)
It works when the application is deployed as exploded WAR. It used to work with compressed WAR, too. Yesterday, I did a clean and rebuild of project in Eclipse, and it just stopped working.
When I check the resource root:
logger.info(this.getClass().getResource("/").toExternalForm());
I get this:
file:/C:/JBoss/wildfly8.1.0.CR1/modules/system/layers/base/org/jboss/as/ejb3/main/timers/
So, no wonder it doesn't work. It probably has something to do with JBoss module loading, but I don't know if this is a bug or normal behavior.
I found various similar problems on StackOverflow, but no applicable solution. One of the suggestions is to use ServletContext like so:
#Resource
private WebServiceContext wsContext;
...
ServletContext servletContext = (ServletContext)this.wsContext.getMessageContext()
.get(MessageContext.SERVLET_CONTEXT);
servletContext.getResource(resourcePath);
But, when I try to obtain MessageContext in this manner, I get an IllegalStateException. So I am basically stuck. Any ideas?
I ran into this same problem, and rather than define the resource as a shared module, I ended up working around this by using a ServletContextListener in my WAR.
In the contextInitialized method, I got the ServletContext from the ServletContextEvent and used its getResource("/WEB-INF/myResource") to get the URL to the resource inside my WAR file. It appears that in the ServletContextListener, the .getResource() method resolves as expected rather than to the "/modules/system/layers/base/org/jboss/as/ejb3/main/timers/" url. That URL can then be stored in the ServletContext for later use by your servlets or in an injected ApplicationScoped CDI bean.
#WebListener
public class ServletInitializer implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
try {
final ServletContext context = sce.getServletContext();
final URL resourceUrl = context.getResource("/WEB-INF/myResource");
context.setAttribute("myResourceURL", resourceUrl);
} catch (final MalformedURLException e) {
throw new AssertionError("Resource not available in WAR file", e);
}
}
#Override
public void contextDestroyed(ServletContextEvent sce) {}
}
or
#WebListener
public class ServletInitializer implements ServletContextListener {
#Inject
private SomeApplicationScopedBean myBean;
#Override
public void contextInitialized(ServletContextEvent sce) {
try {
final ServletContext context = sce.getServletContext();
final URL resourceUrl = context.getResource("/WEB-INF/myResource");
myBean.setResourceUrl(resourceUrl);
} catch (final MalformedURLException e) {
throw new AssertionError("Resource not available in WAR file", e);
}
}
#Override
public void contextDestroyed(ServletContextEvent sce) {}
}
We had a similar problem and our fault was that we tried to access the static resource through the raw path instead of using the input stream the resource is providing - the following code works for us even when deploying a non-exploded .war-file.
final URL resource = this.getClass().getResource(FILE);
try (final InputStream inputStream = resource.openStream();
final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
final BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
// Use bufferedReader to read the content
} catch (IOException e) {
// ...
}
I finally gave up and put my resource files in a new JBoss module, as described in this link.
https://community.jboss.org/wiki/HowToPutAnExternalFileInTheClasspath
It works, but the downside is that there are two deployment targets so things are more complicated. On the upside, the size of the WAR file is reduced, and I don't have to redeploy the application if only some of the resources have changed.
I was recently trying to figure out how to access a file within my own war in Java. The following is how the java classes and resources are packaged in the war file:
WAR
`-- WEB-INF
`-- classes (where all the java classes are)
`-- resourcefiles
`-- resourceFile1
My target file was resourceFile1. To get that file, I just did the following in code:
InputStream inStream = this.class.getClassLoader().getResourceAsStream("resourcefiles/resourceFile1");
In this case the resource files would need to be in the same folder as the classes folder containing the java classes. Hopefully others find this helpful.
This sample code works for wildfly deployed and tested on openshift.
I think it is a wildfly problem I downland wildfly and tried on local I also get the error.
Check sample project on github
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
#Controller
#RequestMapping
public class FileDownloadController {
private static final Logger logger = LoggerFactory.getLogger(FileDownloadController.class);
private static final String DOC_FILE = "file/ibrahim-karayel.docx";
private static final String PDF_FILE = "file/ibrahim-karayel.pdf";
#RequestMapping(value = "/download/{type}", method = RequestMethod.GET)
public void downloadFile(HttpServletRequest request, HttpServletResponse response,
#PathVariable("type") String type) throws IOException {
File file = null;
InputStream inputStream;
if (type.equalsIgnoreCase("doc")) {
inputStream = getClass().getClassLoader().getResourceAsStream(DOC_FILE);
file = new File(Thread.currentThread().getContextClassLoader().getResource(DOC_FILE).getFile());
} else if (type.equalsIgnoreCase("pdf")) {
inputStream = getClass().getClassLoader().getResourceAsStream(PDF_FILE);
file = new File(Thread.currentThread().getContextClassLoader().getResource(PDF_FILE).getFile());
} else{
throw new FileNotFoundException();
}
if (file == null && file.getName() == null) {
logger.error("File Not Found -> " + file);
throw new FileNotFoundException();
}
String mimeType = URLConnection.guessContentTypeFromName(file.getName());
if (mimeType == null) {
System.out.println("mimetype is not detectable, will take default");
mimeType = "application/octet-stream";
}
System.out.println("mimetype : " + mimeType);
response.setContentType(mimeType);
/* "Content-Disposition : inline" will show viewable types [like images/text/pdf/anything viewable by browser] right on browser
while others(zip e.g) will be directly downloaded [may provide save as popup, based on your browser setting.]*/
response.setHeader("Content-Disposition", String.format("inline; filename=\"" + file.getName() + "\""));
/* "Content-Disposition : attachment" will be directly download, may provide save as popup, based on your browser setting*/
//response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", file.getName()));
response.setContentLength(inputStream.available());
IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
inputStream.close();
}
}
Had the same issue with Wildfly and not-exploded WAR and using Spring and ServletContextResource I have got around it like this:
[org.springframework.core.io.]Resource resource = new ServletContextResource(servletContext, "WEB-INF/classes/resource.png");
In the same #Service class I also had:
#Inject
private ServletContext servletContext;
I decided so:
#Autowired
private final ApplicationContext ctx;
private final Path path = Paths.get("testfiles/load")
ctx.getRosource("classpath:" + path);
I read this solution, that lead us to use getResourceAsStream(...) instead of getResource() inside Wildfly. I just test it on Wildfly 19 with myApp.ear deployed from console.
I'm trying to write a test for a Mule flow that will involve dropping a file in a location, waiting for it to be processed by my flow and compare the output to see if it has been transformed correctly. My flow looks as follows:
<flow name="mainFlow" processingStrategy="synchronous">
<file:inbound-endpoint name="fileIn" path="${inboundPath}">
<file:filename-regex-filter pattern="myFile.csv" caseSensitive="true"/>
</file:inbound-endpoint>
...
<file:outbound-endpoint path="${outboundPath}" outputPattern="out.csv"/>
</flow>
Is there a way I can access the inboundPath and outboundPath Mule properties inside of my test class so that I can drop files and wait for output in the correct places?
The test class I'm using is:
public class MappingTest extends BaseFileToFileFunctionalTest {
#Override
protected String getConfigResources() {
return "mappingtest.xml";
}
#Test
public void testMapping() throws Exception {
dropInputFileIntoPlace("myFile.csv");
waitForOutputFile("out.csv", 100);
assertEquals(getExpectedOutputFile("expected-out.csv"), getActualOutputFile("out.csv"));
}
}
Which extends this class:
public abstract class BaseFileToFileFunctionalTest extends FunctionalTestCase {
private static final File INPUT_DIR = new File("/tmp/muletest/input");
private static final File OUTPUT_DIR = new File("/tmp/muletest/output");
private static final Charset CHARSET = Charsets.UTF_8;
#Before
public void setup() {
new File("/tmp/muletest/input").mkdirs();
new File("/tmp/muletest/output").mkdirs();
empty(INPUT_DIR);
empty(OUTPUT_DIR);
}
private void empty(File inputDir) {
for (File file : inputDir.listFiles()) {
file.delete();
}
}
protected File waitForOutputFile(String expectedFileName, int retryAttempts) throws InterruptedException {
boolean polling = true;
int attemptsRemaining = retryAttempts;
File outputFile = new File(OUTPUT_DIR, expectedFileName);
while (polling) {
Thread.sleep(100L);
if (outputFile.exists()) {
polling = false;
}
if (attemptsRemaining == 0) {
VisibleAssertions.fail("Output file did not appear within expected time");
}
attemptsRemaining--;
}
outputFile.deleteOnExit();
return outputFile;
}
protected void dropInputFileIntoPlace(String inputFileResourceName) throws IOException {
File inputFile = new File(INPUT_DIR, inputFileResourceName);
Files.copy(Resources.newInputStreamSupplier(Resources.getResource(inputFileResourceName)), inputFile);
inputFile.deleteOnExit();
}
protected String getActualOutputFile(String outputFileName) throws IOException {
File outputFile = new File(OUTPUT_DIR, outputFileName);
return Files.toString(outputFile, CHARSET);
}
protected String getExpectedOutputFile(String resourceName) throws IOException {
return Resources.toString(Resources.getResource(resourceName), CHARSET);
}
}
As you can see I'm currently creating temporary input/output directories. I'd like to make this part read from the Mule properties if possible? Thanks in advance.
After observing your test classes and code I could see that you want to dynamically create temp folders place files in them. And the flow should read the files from Temp Directory and write output to another Temp directory. Point to be noted is that Mule's Endpoints are created when the configuration is loaded. So the ${inbound} and ${outbound} should be provided to the mule flow by the time they are provided.
So one option can be to create a dummy flow pointing to the temp folders for testing.
or
Create a test properties file pointing to the temp folders and load that to your flow config, so that your flow endpoints will get the temp folder paths.
In any way path cannot be provided to the flow inbound endpoints after they have been created(on config load).
Update1:
As per your comment the solution with option would be like the following.
Seperate the properties loading part of the config into another config.
Like "mapping-core-config.xml,mappingtest.xml" where the mapping-core-config will have the tags to load the properties file.
Now create a test config file for the mapping-core-config.xml file which loads the test properties file. This should be used in your test config. This way without modifying or disturbing your main code, you can test your flows pointing to temp folders.
"mapping-core-test-config.xml,mappingtest.xml"
Note: The test config can reside in the src/test/resources folders.
Hope this helps.