I have a zip file in the server. I would like to download that file on click of a link.
Is there a way to create a link to download the zip file in JSF or PrimeFaces, like below HTML5 download attribute in client side?
<a href="/images/myw3schoolsimage.jpg" download>
The HTML5 download attribute has got nothing to do with it. It just allows you to specify an alternate filename which should appear in Save As dialog.
E.g.
<a href="foo.zip" download="bar.zip" />
will show the Save As dialog with bar.zip as filename, but actually provide content of foo.zip. Do note that the bar.zip doesn't necessarily need to exist in server.
As to your concrete problem, there are several ways of serving a file download in a JSF web application.
Just put that file in public web content folder.
WebContent
|-- META-INF
|-- WEB-INF
|-- files
| `-- foo.zip
|-- page.xhtml
:
Then you can refer it as:
download foo.zip
Or, if it's an external folder and you can't move it into public web content, then just tell the server to publish it. E.g. when you have all those files in /path/to/files path and you're using Tomcat server, then add the following into <Host> element of Tomcat's /conf/server.xml:
<Context docBase="/path/to/files" path="/files" />
Then you can refer it as:
download foo.zip
Or, if you have no control over server configuration somehow, or can't figure the server-specific way of publishing an arbitrary folder as a new web context, or it represents a temporary storage folder which you'd rather not publish into web, then create a web servlet which does the job. Leaving caching and resume outside consideration, it's as simple as:
#WebServlet("/files/*")
public class FileServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String filename = request.getPathInfo().substring(1);
File file = new File("/path/to/files", filename);
response.setHeader("Content-Type", getServletContext().getMimetype(filename));
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
Files.copy(file.toPath(), response.getOutputStream());
}
}
You can refer it the same way as #1:
download foo.zip
Though this is an old question, I would like to add this to #BalusC's answer for completeness (coudn't comment due to low reputation): The third solution by #BalusC ( with #WebServlet) can lead to 'Path Traversal Attack', if copy pasted as is.
You may try the attack(for Linux server) using URL:
<yourApplicationURLUntilContextPath>/files/%C0%AE/%C0%AE/%C0%AE/%C0%AE/%C0%AE/%C0%AE/%C0%AE/%C0%AE/%C0%AE/%C0%AE/etc/passwd
There are various solutions to this problem. One being, add the below check before copying the file to output stream:
if(!file.getAbsolutePath().equals(file.getCanonicalPath()))
{
response.sendError(404);
}
You may refer the link for more solutions to path traversal attack.
Hope it helps some developer...
Related
For my first export script I took the KCEC example and the APIRefExport.chm documentation to create my project by replacing the example code with my own.
I would like to create a clean export script from scratch.
I created a new class library project and called it EmptyExportScript (placeholder). The target framework is .Net 4. The platform target is x86 and the output path is .....\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\. When debugging I would like to start the administration module so I set this path .......\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\.
The option "Make assembly COM-Visible" is checked and I added the Kofax.ReleaseLib.Interop.dll to the references.
For the KfxReleaseScript.cs I added this code
[ClassInterface(ClassInterfaceType.None)]
[ProgId("KFXTS.EmptyExportScript.KfxReleaseScript")]
public class KfxReleaseScript
{
public ReleaseData documentData;
// public KfxReturnValue OpenScript()
// public KfxReturnValue ReleaseDoc()
// public KfxReturnValue CloseScript()
}
For the KfxReleaseScriptSetup.cs I added this code
[ClassInterface(ClassInterfaceType.None)]
[ProgId("KFXTS.EmptyExportScript.KfxReleaseScriptSetup")]
public class KfxReleaseScriptSetup
{
public ReleaseSetupData setupData;
// public KfxReturnValue OpenScript()
// public KfxReturnValue CloseScript()
// public KfxReturnValue RunUI()
// public KfxReturnValue ActionEvent(KfxActionValue actionID, string data1, string data2)
}
Lastly I added a Form to the project when running the UI.
For registration I added a EmptyExportScript.inf with this content
[Scripts]
Empty Export
[Empty Export]
SetupModule=EmptyExportScript.dll
SetupProgID=KFXTS.EmptyExportScript.KfxReleaseScriptSetup
SetupVersion=10.2
ReleaseModule=EmptyExportScript.dll
ReleaseProgID=KFXTS.EmptyExportScript.KfxReleaseScript
ReleaseVersion=10.2
SupportsNonImageFiles=True
SupportsKofaxPDF=True
RemainLoaded=True
SupportsOriginalFileName=False
When building the project .dll and .inf file get placed into the kofax bin directory.
I recognized that other scripts have a .pdb and .dll.config file in there too.
How do I get them?
When trying to install the custom script, I can add it to the script installation manager but I can't install it. There is nothing to install so I think I'm missing the .pdb and .dll.config file.
Is anything else missing?
Thanks for help :)
Kofax does not need a pdb file, but they are handy if you want to debug your connector and attach it to the release.exe process (learn more about them here).
I would not recommend changing the output path itself to Capture\Bin, but rather create a post-build event:
For example, the following line copies all required files to a separate folder under the CaptureSS\Bin folder:
xcopy "$(TargetDir)*" "C:\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\SmartCAP\kec\SmartCAP.KEC.Template\" /Y /S
Having a dll.config file is possible, but rare. I would rather recommend storing process-specific data in a custom storage string object of the respective batch class definition (which has the added benefit that you can just import/export the definition along with the batch class, and that you can display and have it changed it in setup form). Having said all that, back to your initial issue - the connector can't be installed.
COM visibility
The assembly needs to be COM-visible, but you mentioned that it was. For the sake of completeness, here's what you will need to do. Note that the GUID must be unique (only relevant if you copied an existing solution):
If you're installing the connector on a different machine, you will need to register it first using regasm.exe - here's an example:
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" SampleExport.dll /codebase /tlb:SampleExport.tlb
ProgIds
Then, your .inf file needs to contain the precise ProgIDs:
[Scripts]
SampleExport
[SampleExport]
SetupModule=SampleExport.dll
SetupProgID=SampleExport.Setup
SetupVersion=11.0
ReleaseModule=SampleExport.dll
ReleaseProgID=SampleExport
ReleaseVersion=11.0
SupportsNonImageFiles=True
SupportsKofaxPDF=True
Both your ReleaseScript.cs and ReleaseSetupScript.cs files need the correct attribute, for example:
[ProgId("SampleExport")]
public class ReleaseScript
If that all still does not work, please provide us with the detailed error message (to be found at CaptureSV\Logs).
I had to change the file format from UTF-8 to UTF-8 without BOM.
This worked for me.
I've two web content structures (foo and bar) in Liferay 7.0 and I want to store the web contents inside webcontents folders (webcontents/foo and webcontents/bar).
I added two asset publishers, one for each structure, and I also allow the user to create new webcontents through the asset publisher plus '+' icon. However, they are created in the web content root folder (webcontents/). There is any way to dynamicaly save the webcontent that are created through the '+' icon in the asset publisher to a specific folder (based on the template itself, tags, or any other field)?
I used a "ModelListener" for this exact scenario. https://dev.liferay.com/de/develop/tutorials/-/knowledge_base/7-0/model-listeners
If you extend Liferays BaseModelListener you can use the onBeforeCreate() Method for example.
First check the ddmStructure of the current journalArticle and get or create your Folder. Now set the Folder ID for your journalArticle and your done!
I don't think that this can be achieved without customization.
I'd create a service wrapper to determine the Folder e.g. by the Structure's name.
Posting the code as solution suggested by #Viergelenker
public class ArticleSetListenerPortlet extends BaseModelListener<JournalArticle> {
private static final Log LOGGER = LogFactoryUtil.getLog(ArticleSetListenerPortlet.class);
#Override
public void onBeforeCreate(JournalArticle model) throws ModelListenerException {
String structureName = model.getDDMStructure().getName(Locale.US);
long groupId = xxxxx;
List<JournalFolder> journalFolders = JournalFolderLocalServiceUtil.getFolders(groupId);
for(JournalFolder folder : journalFolders) {
if("Foo".equals(folder.getName())) {
model.setFolderId(folder.getFolderId());
LOGGER.info("Set folder as Foo");
}
}
super.onBeforeCreate(model);
}
I would like to be able to upload files in my JSF2.2 web application, so I started using the new <h:inputFile> component.
My only question is, how can I specify the location, where the files will be saved in the server? I would like to get hold of them as java.io.File instances. This has to be implemented in the backing bean, but I don't clearly understand how.
JSF won't save the file in any predefined location. It will basically just offer you the uploaded file in flavor of a javax.servlet.http.Part instance which is behind the scenes temporarily stored in server's memory and/or temporary disk storage location which you shouldn't worry about.
Important is that you need to read the Part as soon as possible when the bean action (listener) method is invoked. The temporary storage may be cleared out when the HTTP response associated with the HTTP request is completed. In other words, the uploaded file won't necessarily be available in a subsequent request.
So, given a
<h:form enctype="multipart/form-data">
<h:inputFile value="#{bean.uploadedFile}">
<f:ajax listener="#{bean.upload}" />
</h:inputFile>
</h:form>
You have basically 2 options to save it:
1. Read all raw file contents into a byte[]
You can use InputStream#readAllBytes() for this.
private Part uploadedFile; // +getter+setter
private String fileName;
private byte[] fileContents;
public void upload() {
fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
try (InputStream input = uploadedFile.getInputStream()) {
fileContents = input.readAllBytes();
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
In case you're not on Java 9 yet and therefore can't use InputStream#readAllBytes(), then head to Convert InputStream to byte array in Java for all other ways to convert InputStream to byte[].
Keep in mind that each byte of an uploaded file costs one byte of server memory. Be careful that your server don't exhaust of memory when users do this too often or can easily abuse your system in this way. If you want to avoid this, better use (temporary) files on local disk file system instead.
2. Or, write it to local disk file system
In order to save it to the desired location, you need to get the content by Part#getInputStream() and then copy it to the Path representing the location.
private Part uploadedFile; // +getter+setter
private File savedFile;
public void upload() {
String fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
savedFile = new File(uploads, fileName);
try (InputStream input = file.getInputStream()) {
Files.copy(input, savedFile.toPath());
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
The uploads folder and the filename is fully under your control. E.g. "/path/to/uploads" and Part#getSubmittedFileName() respectively. Keep in mind that any existing file would be overwritten, you might want to use File#createTempFile() to autogenerate a filename. You can find an elaborate example in this answer.
Do not use Part#write() as some prople may suggest. It will basically rename the file in the temporary storage location as identified by #MultipartConfig(location). Also do not use ExternalContext#getRealPath() in order to save the uploaded file in deploy folder. The file will get lost when the WAR is redeployed for the simple reason that the file is not contained in the original WAR. Always save it on an absolute path outside the deploy folder.
For a live demo of upload-and-preview feature, check the demo section of the <o:inputFile> page on OmniFaces showcase.
See also:
Write file into disk using JSF 2.2 inputFile
How to save uploaded file in JSF
Recommended way to save uploaded files in a servlet application
On this page of the documentation, at the bottom, it says:
You can find full examples of Sphinx-4 configuration file in sources. For example, check the file
sphinx4/src/apps/edu/cmu/sphinx/demo/transcriber/config.xml
Well, I looked, and there is no config.xml in that directory, and there is no such file in any of the other folders inside of demo either.
So where can one find a default config file to use to get started with?
If I just do Configuration configuration = new Configuration();, would that be good enough to start with?
I recently found out that what you suggest is not enough. Take a look at the latest code on the Github repository. There is a default.config.xml file at https://github.com/cmusphinx/sphinx4/tree/master/sphinx4-core/src/main/resources/edu/cmu/sphinx/api, and the path to it is set in the Context class in package edu.cmu.sphinx.api:
public Context(Configuration config)
throws IOException, MalformedURLException
{
this("../sphinx4/sphinx4-core/src/main/resources/edu/cmu/sphinx/api/default.config.xml", config);
}
This is very easy using Glassfish:
Consider my absolute path on unix /apps/static_content/.
Using Glassfish, I will simply define alternate doc root as:
<property name="alternatedocroot_1"
value="from=/static/* dir=/apps/static_content/"/>
When I upload my images and other data files, I can save them to the /apps/static_content directory, and within my JSF page I can display my static content normally as:
<p:graphicsimage value="/static/external_web_app.png"/>
I really need to achieve the same functionality in JBoss AS7
How can I do this?
This question is a little bit old, but answering if someone need to do this with newer versions of JBoss/Wildfly.
JBoss AS was renamed to Wildfly from version 8 (i.e. Wildfly 8 is JBoss AS 8) and Red Hat supported version of JBoss was renamed to JBoss EAP. So this applies to:
Wildfly (any version)
JBoss EAP (from version 7)
First thing to note is that "Alternate doc root" feature in glassfish doesn't work like that. Please take a look at this question for an explanation of the behavior of this feature: Alternate docroot not working on glassfish 4
Now, to answer this question, JBoss/Wildfly is build upon Undertow, that let you do exactly what you need. Refer at this question on how to configure undertow as a web server for static content: How to configure Wildfly to serve static content (like images)?
Option 1: You could try to deploy a separate exploded .war file, and use that for your static content
In your case: In .../jboss-7/standalone/deployments/ there must be a static.war/.
So the uploads go into this directory, and the content is served back the normal way.
As for details, see Is it possible to deploy an exploded war file (unzipped war) in JBoss AS 7
As pointed out by BalusC: You must not redeploy/remove this directory, as soon as data has been uploaded. You should have a regular backup of this directory.
As far as I know this is the only possibility to do it by configuration/setup only.
Option 2: Create separate webapp with name static.war. Add a servlet to stream the static content
This way there is no need to upload/store the files into the file system below ../deployments/, it could be any directory, but you need an additional servlet, so it's solved programatically.
A simple streaming servlet could look like this (just streaming - no authentication etc.):
public class DownloadServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
final File dir = new File("/var/cms/storage/");
final String start = "/static/";
final String relativePath = request.getRequestURI().substring(
request.getRequestURI().indexOf(start) + start.length());
final File file = new File(dir, relativePath);
final String ct = URLConnection.guessContentTypeFromName(file.getName());
response.setContentType(ct);
final InputStream is =
new BufferedInputStream(new FileInputStream(file));
try {
final boolean closeOs = true;
org.apache.commons.fileupload.util.Streams.copy
(is, response.getOutputStream(), closeOs);
} finally {
is.close();
}
}
Map all URLs to this servlet:
<servlet-mapping>
<servlet-name>DownloadServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
The name static.war provides the /static/ web context, so that should make it compatible with the URLs in your code.
If you explore jboss directory you will find that there are many you can use to store different type of data like jboss.serer.data.dir .
You can try asking this directory path via system properties and store in a folder the data your services are using, under such directory.
String path = System.getProperty("jboss.server.data.dir");
Then you can use path as you want, if is just static as shown in your example you set directly the name of the directory.
This should work, I hope :p
ps: as the previous answer suggest the saved data will keep in the directory, and you must not redeploy/remove this directory.. It will keep your data there..