I've deployed a webapp (war) to Glassfish v3 and I am trying to get it to read from properties defined in a custom resource.
In my app, I've defined the properties as:
#Resource(mappedName = "TestServletProperties")
private Properties properties;
and make use of it like this:
protected void doGet(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException,
java.io.IOException
{
String propertyOne = properties.getProperty("testServlet.propertyOne");
String propertyTwo = properties.getProperty("propertyTwo");
StringBuffer buffer = new StringBuffer("Properties Retrieved\n");
buffer.append("Property One: " + propertyOne + "\n");
buffer.append("Property Two: " + propertyTwo + "\n");
try
{
response.getWriter().write(buffer.toString());
}
catch (Exception ex)
{
try
{
log.warn("Exception thrown", ex);
response.getWriter().write(ex.getStackTrace().toString());
}
catch (IOException io)
{
log.warn("IOException thrown", io);
}
}
}
In Glassfish, I've created a JNDI Custom Resource called TestServletProperties of type java.util.Properties and using factory class org.glassfish.resources.custom.factory.PropertiesFactory. In the resource there is one property "fileName" with its value set to the absolute path of the properties file:
/Program Files/glassfishv3/glassfish/domains/domain1/applications/Test/WEB-INF/classes/TestServlet_lab.properties
I've also tried
c:\Program Files\glassfishv3\glassfish\domains\domain1\applications\Test\WEB-INF\classes\TestServlet_lab.properties
I have confirmed that the file exists and contains the referenced properties. Unfortunately, I'm getting back "null" for both values in my response.
Any thoughts?
The solution is that you have to use the fully qualified "org.glassfish.resources.custom.factory.PropertiesFactory.fileName" versus just "fileName".
The reason might be that you have a web.xml file with the header of a 2.4 (or older) servlet version.
#Resource and other annotations are only processed if you have at least version 2.5 in the header of web.xml. Be sure that you do not simply change the version but copy and paste the new header from somewhere as the namespace is different.
Hope this helps
Related
I want my code to be called everytime someone views or downloads anything in Document And Media:
View:
Download:
The content URLs of the view and download (to which the HTTP response is an actual preview image or PDF itself being transfered) are respectively:
http://localhost:8080/documents/20143/0/invoice_ABC_2017.10.27.pdf/c44fd479-331b-f393-7879-973c5cecf086?version=1.0&previewFileIndex=1
http://localhost:8080/documents/20143/0/invoice_ABC_2017.10.27.pdf/c44fd479-331b-f393-7879-973c5cecf086?download=true
The responses to both requests seems to be built by WebServerServlet.sendFile, a part of Liferay which is unfortunately not an OSGi module.
My first instinct would have been to implement ModelListener, but it only has methods for creation/update/deletion events, nothing for read events.
How to intercept these events in Liferay? (7 EE DXP)
Model listeners are connected to the CRUD operation that can happen on an entity.
You could attach your self to the download action. Have a look here https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/converting-strutsactionwrappers-to-mvccommands
Preview
Preview (in the sense of the preview page being displayed by any user) can be intercepted by deploying a component that takes the place of the MVCRenderCommand.class service. To do that, copy Liferay's ViewFileEntryMVCRenderCommand.java and add your code in the render method:
#Component(
property = {
"service.ranking:Integer=100",
"javax.portlet.name=" + DLPortletKeys.DOCUMENT_LIBRARY,
"javax.portlet.name=" + DLPortletKeys.DOCUMENT_LIBRARY_ADMIN,
"javax.portlet.name=" + DLPortletKeys.MEDIA_GALLERY_DISPLAY,
"mvc.command.name=/document_library/view_file_entry"
},
service = MVCRenderCommand.class
)
public class MyViewFileEntryMVCRenderCommand implements MVCRenderCommand {
#Override
public String render(
RenderRequest renderRequest, RenderResponse renderResponse)
throws PortletException {
DoMyAuditThing();
[...]
}
[...]
}
Download
Download (in the sense of a Document and Media being actually downloaded) can be intercepted by creating a Servlet Filter (copied from the Liferay plugin samples) with this liferay-hook.xml configuration:
(UPDATE: Just after writing this code I realized that there is now a better way to write Servlet Filters)
<hook>
<servlet-filter>
<servlet-filter-name>Sample Filter</servlet-filter-name>
<servlet-filter-impl>com.liferay.sampleservletfilter.hook.filter.SampleFilter</servlet-filter-impl>
<init-param>
<param-name>hello</param-name>
<param-value>world</param-value>
</init-param>
</servlet-filter>
<servlet-filter-mapping>
<servlet-filter-name>Sample Filter</servlet-filter-name>
<before-filter>SSO Open SSO Filter</before-filter>
<url-pattern>/documents/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</servlet-filter-mapping>
</hook>
Note the <url-pattern>/documents/*</url-pattern> part.
The Filter class:
public class SampleFilter implements Filter {
#Override
public void doFilter(
ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException {
String uri = (String)servletRequest.getAttribute(
WebKeys.INVOKER_FILTER_URI);
// Extract information
String[] tokens = uri.split("/");
if(tokens.length < 6) {
System.out.println("Failed to parse download URI (Too few slashes): " + uri);
filterChain.doFilter(servletRequest, servletResponse);
return;
}
long groupId;
try {
groupId = Long.parseLong(tokens[2]);
}
catch(NumberFormatException e) {
System.out.println("Failed to parse download URI (Group not a number): " + uri);
filterChain.doFilter(servletRequest, servletResponse);
return;
}
String uuid = tokens[5];
System.out.println("group:" + groupId + " uuid:" + uuid);
DLFileEntry fileEntry = DLFileEntryLocalServiceUtil.fetchDLFileEntryByUuidAndGroupId(uuid, groupId);
// Send it to your audit
[...]
filterChain.doFilter(servletRequest, servletResponse);
}
}
A problem is that it seems to also catch unnecessary events when showing the Document and Media page... I investigate.
You could implement the Service Wrapper and in particular the getFile method. This method it’s called when the user request the download of the file.
I am importing a library that reads from the file system instead of my web archive's resource folder. I want to be able to essentially mock that file by adding an asset with that path using ShrinkWrap, so I can run tests on my build server without guaranteeing the file system has all these files. I tried to add a String Asset in the appropriate path, but the code can't find that asset. Here's an example of what I'm trying to achieve.
Rest Resource
#Path("/hello-world")
public class HelloWorldResource {
#GET
public Response getHelloWorld(){
return Response.ok(getFileContent()).build();
}
private String getFileContent() {
StringBuilder builder = new StringBuilder();
try {
BufferedReader bufferedReader = new BufferedReader(
new FileReader(
"/usr/myFile.txt"));
String line = bufferedReader.readLine();
while (line != null) {
builder.append(line);
line = bufferedReader.readLine();
}
}
catch (Exception e) {
e.printStackTrace();
}
return builder.toString();
}
}
Test
#RunWith(Arquillian.class)
public class HelloWorldResourceTest {
#Deployment
public static WebArchive createDeployment()
{
WebArchive webArchive = ShrinkWrap
.create(WebArchive.class)
.addPackages(true,
HelloWorldApplication.class.getPackage(),
HelloWorldResource.class.getPackage(),
Hello.class.getPackage())
.add(new StringAsset("Blah"),"/usr/myFile.txt")
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
System.out.println("WebArchive: " + webArchive.toString(true));
return webArchive;
}
#Test
#RunAsClient
public void testHello(
#ArquillianResteasyResource("hello-world") final WebTarget webTarget)
{
final Response response = webTarget
.request(MediaType.APPLICATION_JSON)
.get();
String hello = response.readEntity(String.class);
System.err.println("Hello: " + hello);
Assert.assertEquals("Status is not OK", response.getStatus(), 200);
}
}
Web Archive toString
/WEB-INF/
/WEB-INF/classes/
/WEB-INF/classes/com/
/WEB-INF/classes/com/
/WEB-INF/classes/com/
/WEB-INF/classes/com/helloworld/
/WEB-INF/classes/com/helloworld/application/
/WEB-INF/classes/com/helloworld/application/HelloWorldApplication.class
/WEB-INF/classes/com/helloworld/resource/
/WEB-INF/classes/com/helloworld/resource/HelloWorldResourceTest.class
/WEB-INF/classes/com/helloworld/resource/HelloWorldResource.class
/WEB-INF/classes/com/helloworld/dataobjects/
/WEB-INF/classes/com/helloworld/dataobjects/Hello.class
/WEB-INF/beans.xml
/usr/
/usr/myFile.txt
I get the following error:
java.io.FileNotFoundException: /usr/myFile.txt (No such file or
directory)
Seems like ShrinkWrap is adding /usr/myFile.txt as a relative path within the archive instead of making it seem like /usr/myFile.txt is at the root directory of my file system. Is there any way I can get ShrinkWrap to do what I want?
Shrinkwrap is intended to create archives, so the API is scoped to create assets within the archive you are creating. If you want to have resources created in the regular filesystem simply use JDK, there is nothing Shrinkwrap could help you with.
Alternatively, if possible, change your resource to read resources from the classpath, not filesystem path. With this approach, you can easily swap content for the test using Shrinkwrap as you are trying now with your example.
I've been struggling with this for the past 3 days now, I keep getting the following exception when I try upload a file in my spring boot project.
org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
I'm not sure if it makes a differance but I am deploying my application as a war onto weblogic,
here is my controller
#PostMapping
public AttachmentDto createAttachment(#RequestParam(value = "file") MultipartFile file) {
logger.info("createAttachment - {}", file.getOriginalFilename());
AttachmentDto attachmentDto = null;
try {
attachmentDto = attachmentService.createAttachment(new AttachmentDto(file, 1088708753L));
} catch (IOException e) {
e.printStackTrace();
}
return attachmentDto;
}
multi part beans I can see in spring boot actuator
payload seen in chrome
Name attribute is required for #RequestParm 'file'
<input type="file" class="file" name="file"/>
You can try use #RequestPart, because it uses HttpMessageConverter, that takes into consideration the 'Content-Type' header of the request part.
Note that #RequestParam annotation can also be used to associate the part of a "multipart/form-data" request with a method argument supporting the same method argument types. The main difference is that when the method argument is not a String, #RequestParam relies on type conversion via a registered Converter or PropertyEditor while #RequestPart relies on HttpMessageConverters taking into consideration the 'Content-Type' header of the request part. #RequestParam is likely to be used with name-value form fields while #RequestPart is likely to be used with parts containing more complex content (e.g. JSON, XML).
Spring Documentation
Code:
#PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public AttachmentDto createAttachment(#RequestPart("file") MultipartFile file) {
logger.info("Attachment - {}", file.getOriginalFilename());
try {
return attachmentService.createAttachment(new AttachmentDto(file, 1088708753L));
} catch (final IOException e) {
logger.e("Error creating attachment", e);
}
return null;
}
You are using multi part to send files so there is nothing much configuration to do to get desired result.
I m having the same requirement and my code just run fine :
#RestController
#RequestMapping("/api/v2")
public class DocumentController {
private static String bucketName = "pharmerz-chat";
// private static String keyName = "Pharmerz"+ UUID.randomUUID();
#RequestMapping(value = "/upload", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA)
public URL uploadFileHandler(#RequestParam("name") String name,
#RequestParam("file") MultipartFile file) throws IOException {
/******* Printing all the possible parameter from #RequestParam *************/
System.out.println("*****************************");
System.out.println("file.getOriginalFilename() " + file.getOriginalFilename());
System.out.println("file.getContentType()" + file.getContentType());
System.out.println("file.getInputStream() " + file.getInputStream());
System.out.println("file.toString() " + file.toString());
System.out.println("file.getSize() " + file.getSize());
System.out.println("name " + name);
System.out.println("file.getBytes() " + file.getBytes());
System.out.println("file.hashCode() " + file.hashCode());
System.out.println("file.getClass() " + file.getClass());
System.out.println("file.isEmpty() " + file.isEmpty());
/**
BUSINESS LOGIC
Write code to upload file where you want
*****/
return "File uploaded";
}
None of the above solutions worked for me, but when I digged deeper i found that spring security was the main culprit. Even if i was sending the CSRF token, I repeatedly faced the issue POST not supported. I came to know that i was receiving forbidden 403 when i inspected using developer tools in google chrome and saw the status code in the network tab. I added the mapping to ignoredCsrfMapping in Spring Security configuration and then it worked absolutely without any other flaw. Don't know why i was not allowed to post multipart data by security. Some of the mandatory setting that needs to be stated in application.properties file are as follows:
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
spring.http.multipart.max-file-size=10MB
spring.http.multipart.max-request-size=10MB
spring.http.multipart.enabled=true
I am new to Java so forgive me for my lack of knowledge. I am trying to utilize a properties file in my web app. While researching I found this article http://commons.apache.org/configuration/howto_properties.html which seemed pretty straight forward so I attempted to implement this. I attempted to implement as follows :
Configuration config = new PropertiesConfiguration("stream.bundle.config");
I have tried stream.bundle.config, bundle.config and many other combinations but every time I get back an exception that says Cannot locate configuration source. The file is in a folder under src called bundle. My question is a) where should the file be? b) how should I reference it. I apologize for my lack of knowledge. Thanks in advance.
update:
I also tried
FileInputStream in;
Properties p = new Properties();
try{
in = new FileInputStream("config.properties");
p.load(in);
}
catch(Exception e){
System.out.println("Error: " + e);
}
and I get java.io.FileNotFoundException: config.properties (The system cannot find the file specified) or java.io.FileNotFoundException: config (The system cannot find the file specified)
Regarding a) where should the file be:
in the current directory
in the user home directory
in the classpath
If you consider using Java's Properties you have to get an InputStream some way. If you're loading the properties from a class in the package, you have to use:
getClass().getResourceAsStream("resource.properties");
and if the class is in another package:
getClass().getResourceAsStream("some/pkg/resource.properties");
You can try loading the properties via the ClassLoader:
ClassLoader.getResourceAsStream ("some/pkg/resource.properties");
If you have a ServletContext, you can use:
ServletContext.getResourceAsStream(..)
EDIT: you should reference your file by the full name (filename+extension). So your first
try should have been:
Configuration config = new PropertiesConfiguration("config.properties");
Try this:
Properties properties = new Properties();
try
{
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("xyz.properties"));
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
Seems pretty straight forward. Documentation at http://velocity.apache.org/engine/devel/developer-guide.html#Configuring_Logging
says to set the runtime.log property. Here's what I got for all my properties.
velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, templatesPath);
velocityEngine.setProperty("runtime.log", "/path/to/my/file/velocity.log");
velocityEngine.setProperty("resource.loader", "string");
velocityEngine.setProperty("string.resource.loader.class", "org.apache.velocity.runtime.resource.loader.StringResourceLoader");
velocityEngine.setProperty("string.resource.loader.repository.class", "org.apache.velocity.runtime.resource.util.StringResourceRepositoryImpl");
Not finding any log file where I told it to place it and instead finding the new errors placed into old (folder of initialization) location. Any ideas? :D
i had similar problem when setting at runtime some options. I figured out those problem whit a custom VelocityBuilder and an external velocity.properties file where you can put all the runtime properties.
Here is the code:
public class BaseVelocityBuilder implements VelocityBuilder {
private VelocityEngine engine;
private Log logger = LogFactory.getLog(getClass());
#Autowired
private WebApplicationContext webApplicationContext;
public VelocityEngine engine() {
if(engine == null) {
engine = new VelocityEngine();
Properties properties = new Properties();
InputStream in = null;
try {
in = webApplicationContext.getServletContext().getResourceAsStream("/WEB-INF/velocity.properties");
properties.load(in);
engine.init(properties);
} catch (IOException e) {
e.printStackTrace();
logger.error("Error loading velocity engine properties");
throw new ProgramException("Cannot load velocity engine properties");
}
IOUtils.closeQuietly(in);
}
return engine;
}
}
See this line:
in = webApplicationContext.getServletContext().getResourceAsStream("/WEB-INF/velocity.properties");
properties.load(in);
engine.init(properties);
So i have a velocity.properties file in /WEB-INF where i put some configuration:
resource.loader = webinf, class
webinf.resource.loader.description = Framework Templates Resource Loader
webinf.resource.loader.class = applica.framework.library.velocity.WEBINFResourceLoader
webapp.resource.loader.class = org.apache.velocity.tools.view.servlet.WebappLoader
webapp.resource.loader.path =
file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path =
class.resource.loader.description = Velocity Classpath Resource Loader
class.resource.loader.class = org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
runtime.log='/pathYouWant/velocity.log'
In the end in your application.xml :
<bean class="applica.framework.library.velocity.BaseVelocityBuilder" />
In this way you can have for example different file log for different application and when you give the war in production, the sysadm can change the properties due to env configuration of the production server.