Writing my own image importer, pictures are not recognized as pictures after import - broadleaf-commerce

i am writing my own image import for my product catalog. I want to read the images from the local filesystem and store them in the configured assets folder. The import is very simple for now. Its one controller in the admin project and i trigger it by calling an url.
It is creating the files along with the folder structure and the files seem to have the same filesize, but somehow they get messed up along the way and they are not readable as images anymore (picture viewers wont open them). Any ideas why its being messed up ?
here the code:
#Controller("blImageImportController")
#RequestMapping("/imageimport")
public class ImageImportController extends AdminAbstractController {
#Value("${image.import.folder.location}")
private String importFolderLocation;
#Resource(name = "blStaticAssetService")
protected StaticAssetService staticAssetService;
#Resource(name = "blStaticAssetStorageService")
protected StaticAssetStorageService staticAssetStorageService;
#RequestMapping(method = {RequestMethod.GET})
public String chooseMediaForMapKey(HttpServletRequest request,
HttpServletResponse response,
Model model
) throws Exception {
File imageImportFolder = new File(importFolderLocation);
if (imageImportFolder.isDirectory()) {
Arrays.stream(imageImportFolder.listFiles()).forEach(directory ->
{
if (directory.isDirectory()) {
Arrays.stream(directory.listFiles()).forEach(this::processFile);
}
});
}
return "";
}
private void processFile(File file) {
FileInputStream fis = null;
try {
HashMap properties = new HashMap();
properties.put("entityType", "product");
properties.put("entityId", file.getParentFile().getName());
fis = new FileInputStream(file);
StaticAsset staticAsset = this.staticAssetService.createStaticAsset(fis, file.getName(), file.length(), properties);
this.staticAssetStorageService.createStaticAssetStorage(fis, staticAsset);
fis.close();
} catch (Exception e) {
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}

There is a check in the StaticAssetService to try to detect this as an image (see https://github.com/BroadleafCommerce/BroadleafCommerce/blob/b55848f/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/file/service/StaticAssetServiceImpl.java#L217-L220). If it detected this correctly, you should get back an ImageStaticAssetImpl in the result to that call.
The flipside of this is the controller that actually reads the file (the StaticAssetViewController that renders a StaticAssetView). One of the things that the StaticAssetView does is set a response header for mimeType which the browser uses to render. This is set by this piece in the StaticAssetStorageService: https://github.com/BroadleafCommerce/BroadleafCommerce/blob/b55848f837f26022a620f0c2c143eed7902ba3f1/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/file/service/StaticAssetStorageServiceImpl.java#L213. I suspect that is the root of your problem.
Also just a note, sending those properties is not necessary when you are uploading the file yourself. That is mainly used in the admin when you are uploading an image for a specific entity (like a product or a category).

Related

Uploading file in JSF (Need correct file pathway) [duplicate]

This question already has an answer here:
How to upload file using JSF 2.2 <h:inputFile>? Where is the saved File?
(1 answer)
Closed 5 years ago.
I am trying to get my JSF site to upload a picture to the server, but am having a time of it. I've found 4 methodologies to do, but I'd like to use h:InputFile as it seems the most direct.
It would seem I just need to supply the upload path correctly.
After adding #MultipartConfig I no longer get an exception, but I can't verify the file is uploaded or see any error.
public void AddPicture()
{
ConnInfo HitIt = new ConnInfo();
try
{
HitIt.save(fileCelebrityToAdd);
}
catch(Exception ex)
{
//?
}
}
#MultipartConfig(location="C:\\local\\pathway\\Netbeans\\project\\web\\Pictures\\items\\")
public class ConnInfo
{
private String uploadLocation;
public ConnInfo()
{
//uploadLocation = ".\\Pictures\\items\\";
uploadLocation = "C:\\local\\pathway\\Netbeans\\project\\web\\Pictures\\items\\";
}
public boolean TryOut(Part file) throws IOException
{
String monkey = uploadLocation+getFilename(file);
try
{
file.write(monkey);
}
catch(Exception ex)
{
return false;
}
return true;
}
}
Hopefully I've copied the necessary information correctly.
After going back and rereading all the articles I had bookmarked, it was actually the from the one Tam had suggested that I was able to strip out some information.
I didn't need the AJAX, or the #MultipartConfig, and my previous attempt was somehow incorrect, but the follow method allowed me to successfully upload a picture where I wanted it:
public boolean SaveHer(Part file)
{
String monkey = getFilename(file);
try (InputStream input = file.getInputStream())
{
Files.copy(input, new File(uploadLocation, monkey).toPath());
}
catch (IOException e)
{
// Show faces message?
return false;
}
return true;
}

Google Custom Search API - Search Results

I have somewhat lost touch with custom search engines ever since Google switched from its more legacy search engine api in favor of the google custom search api. I'm hoping someone might be able to tell me whether a (pretty simple) goal can be accomplished with the new framework, and potentially any starting help would be great.
Specifically, I am looking to write a program which will read in text from a text file, then use five words from said document in a google search - the point being to figure out how many results accrue from said search.
An example input/output would be:
Input: "This is my search term" -- quotations included in the search!
Output: there were 7 total results
Thanks so much, all, for your time/help
First you need to create a Google Custom Search project inside you google account.
From this project you must obtain a Custom Search Engine ID , known as cx parameter. You must also obtain a API key parameter. Both of these are available from your Google Custom Search API project inside your google account.
Then, if you prefer Java , here's a working example:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class GoogleCustonSearchAPI {
public static void main(String[] args) throws Exception {
String key="your_key";
String qry="your_query";
String cx = "your_cx";
//Fetch urls
URL url = new URL(
"https://www.googleapis.com/customsearch/v1?key="+key+"&cx="+cx+"&q="+ qry +"&alt=json&queriefields=queries(request(totalResults))");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
//Remove comments if you need to output in JSON format
/*String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}*/
//Print the urls and domains from Google Custom Search String searchResult;
while ((searchResult = output.readLine()) != null) {
int startPos=searchResult.indexOf("\"link\": \"")+("\"link\": \"").length();
int endPos=searchResult.indexOf("\",");
if(searchResult.contains("\"link\": \"") && (endPos>startPos)){
String link=searchResult.substring(startPos,endPos);
if(link.contains(",")){
String tempLink = "\"";
tempLink+=link;
tempLink+="\"";
System.out.println(tempLink);
}
else{
System.out.println(link);
}
System.out.println(getDomainName(link));
}
}
conn.disconnect();
}
public static String getDomainName(String url) throws URISyntaxException {
URI uri = new URI(url);
String domain = uri.getHost();
return domain.startsWith("www.") ? domain.substring(4) : domain;
}
The "&queriefields=queries(request(totalResults))" is what makes the difference and gives sou what you need. But keep in mind that you can perform only 100 queries per day for free and that the results of Custom Search API are sometimes quite different from the those returned from Google.com search
If anybody would still need some example of CSE (Google Custom Search Engine) API, this is working method
public static List<Result> search(String keyword){
Customsearch customsearch= null;
try {
customsearch = new Customsearch(new NetHttpTransport(),new JacksonFactory(), new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
try {
// set connect and read timeouts
httpRequest.setConnectTimeout(HTTP_REQUEST_TIMEOUT);
httpRequest.setReadTimeout(HTTP_REQUEST_TIMEOUT);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
List<Result> resultList=null;
try {
Customsearch.Cse.List list=customsearch.cse().list(keyword);
list.setKey(GOOGLE_API_KEY);
list.setCx(SEARCH_ENGINE_ID);
Search results=list.execute();
resultList=results.getItems();
}
catch ( Exception e) {
e.printStackTrace();
}
return resultList;
}
This method returns List of Result Objects, so you can iterate through it
List<Result> results = new ArrayList<>();
try {
results = search(QUERY);
} catch (Exception e) {
e.printStackTrace();
}
for(Result result : results){
System.out.println(result.getDisplayLink());
System.out.println(result.getTitle());
// all attributes
System.out.println(result.toString());
}
I use gradle dependencies
dependencies {
compile 'com.google.apis:google-api-services-customsearch:v1-rev57-1.23.0'
}
Don't forget to define your own GOOGLE_API_KEY, SEARCH_ENGINE_ID (cx), QUERY and HTTP_REQUEST_TIMEOUT (ie private static final int HTTP_REQUEST_TIMEOUT = 3 * 600000;)

View cloudinary images/vid through android app

I have looked in so many places on a lead on how or if it is possible to view images uploaded to cloudinary, by a specific tag through Android studio app i am trying to build.
I was able to implement the upload option by user, with adding a tag to the images, and public id, also retrieving these information, but i cant find anything on how to view these images, for example i want the app to be able to view all images with a specific tag ( username ) to the user that uploaded the pictures, and could delete them ? and also view other images uploaded by other user with no other permission.
Is it possible and how !?
I ended up with this code, and i encountered a problem;
#Override
public void onClick(View v) {
new JsonTask().execute("http://res.cloudinary.com/cloudNAme/video/list/xxxxxxxxxxxxxxxxxxx.json");
// uploadExtract();
}
});
public class JsonTask extends AsyncTask<String ,String,String> {
#Override
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
In the log i get the following;
03-28 12:36:14.726 20333-21459/net.we4x4.we4x4 W/System.err: java.io.FileNotFoundException: http://res.cloudinary.com/we4x4/video/list/3c42f867-8c3a-423b-89e8-3fb777ab76f8.json
i am not sure if my understanding is correct of the method or i am doing something wrong ? since in the Admin API Docs. or cloudinary the syntax for the HTML request and also in the suggested page by Nadav:
https://support.cloudinary.com/hc/en-us/articles/203189031-How-to-retrieve-a-list-of-all-resources-sharing-the-same-tag-
this should've returned a JSON ?
The following feature allows you to retrieve a JSON formatted list of resources that which share a common tag:
https://support.cloudinary.com/hc/en-us/articles/203189031-How-to-retrieve-a-list-of-all-resources-sharing-the-same-tag-
Note that image removal will coerce you to use server-side code (e.g. JAVA), since deleting via Cloudinary requires a signature that is based on your API_SECRET.

Downloads with JavaFX WebView

my web application offers a download. Javascript creats at the click the url (it depends on the user input) and the browser should open it, so that the page isn't reloaded.
For that, I think I have to alternatives:
// Alt1:
window.open(pathToFile);
// Alt2:
var downloadFrame = document.getElementById('downloads');
if (downloadFrame === null) {
downloadFrame = document.createElement('iframe');
downloadFrame.id = 'downloads';
downloadFrame.style.display = 'none';
document.body.appendChild(downloadFrame);
}
downloadFrame.src = pathToFile;
Both works under Firefox. Problem with open new window method: If the creation of the file at the server needs more time, the new empty tab will be closed late.
Problem with iframe: If there is an error at the server, no feedback is given.
I think at firefox the iframe is the better solution. But the web application must run with an JavaFX WebView, too. JavaFX haven't a download feature, I have to write it. One possible way is to listen on the location property:
final WebView webView = new WebView();
webView.getEngine().locationProperty().addListener(new ChangeListener<String>() {
#Override public void changed(ObservableValue<? extends String> observableValue, String oldLoc, String newLoc) {
if (newLoc.cotains("/download")) {
FileChooser chooser = new FileChooser();
chooser.setTitle("Save " + newLoc);
File saveFile = chooser.showSaveDialog(webView.getEngine().getScene().getWindow());
if (saveFile != null) {
BufferedInputStream is = null;
BufferedOutputStream os = null;
try {
is = new BufferedInputStream(new URL(newLoc).openStream());
os = new BufferedOutputStream(new FileOutputStream(saveFile));
while ((readBytes = is.read()) != -1) {
os.write(b);
}
} finally {
try { if (is != null) is.close(); } catch (IOException e) {}
try { if (os != null) os.close(); } catch (IOException e) {}
}
}
}
}
}
There are some problems:
The download start depends on a part of the url, because JafaFX supports no access to the http headers (that is bearable)
If the user starts the download with the same url two times, only the first download works (the change event only fires, if the url is new). I can crate unique urls (with #1, #2 and so on at the end). But this is ugly.
Only the "window.open(pathToFile);" method works. Loading an iframe don't fire the change location event of the website. That is expectable but I haven't found the right Listener.
Can someone help me to solve 2. or 3.?
Thank you!
PS: Sorry for my bad english.
edit:
For 2. I found a way. I don't know if it is a good one, if it is performant, if the new webview is deleted or is in the cache after download, ....
And the user don't get an feedback, when some a problem is raised:
webView.getEngine().setCreatePopupHandler(new Callback<PopupFeatures, WebEngine>() {
#Override public WebEngine call(PopupFeatures config) {
final WebView downloader = new WebView();
downloader.getEngine().locationProperty().addListener(/* The Listener from above */);
return downloader.getEngine();
}
}
I think you may just need to use copyURLtoFile to get the file...call that when the location changes or just call that using a registered java class. Something like this:
org.apache.commons.io.FileUtils.copyURLToFile(new URL(newLoc), new File(System.getProperty("user.home")+filename));
Using copyURLToFile the current page doesn't have to serve the file. I think registering the class is probably the easiest way to go... something like this:
PHP Code:
Download $filename
Java (in-line class in your javafx class/window... in this case my javafx window is inside of a jframe):
public class JavaApp {
JFrame cloudFrameREF;
JavaApp(JFrame cloudFrameREF)
{
this.cloudFrameREF = cloudFrameREF;
}
public void getfile(String filename) {
String newLoc = "http://your_web_site.com/send_file.php?filename=" + filename;
org.apache.commons.io.FileUtils.copyURLToFile(new URL(newLoc), new File(System.getProperty("user.home")+filename));
}
}
This part would go in the main javafx class:
Platform.runLater(new Runnable() {
#Override
public void run() {
browser2 = new WebView();
webEngine = browser2.getEngine();
appREF = new JavaApp(cloudFrame);
webEngine.getLoadWorker().stateProperty().addListener(
new ChangeListener<State>() {
#Override public void changed(ObservableValue ov, State oldState, State newState) {
if (newState == Worker.State.SUCCEEDED) {
JSObject win
= (JSObject) webEngine.executeScript("window");
// this next line registers the JavaApp class with the page... you can then call it from javascript using "app.method_name".
win.setMember("app", appREF);
}
}
});
You may not need the frame reference... I was hacking some of my own code to test this out and the ref was useful for other things...

How to download excel file from web application?

I'm using Wicket (not sure if it matters) but I'm using Workbook to create an excel file for a user to download. But I'm not sure how exactly to do this. What I would like to happen is the user clicks the button, a log is created and a prompt is given to the user to open (and save to temp files) or to save to their computer. The file is then deleted from the server side, or maybe it is stored in the User's session and deleted at end of session.
Can someone point me in the right direction? If I can have the file not saved in the session at all, that'd be create and have it just have it sent to the client using FileOutputStream somehow..
here is my current code:
private void excelCreator()
{
Workbook workbook = new HSSFWorkbook();
Sheet sheet = workbook.createSheet(WorkbookUtil.createSafeSheetName("SSA User ID " + currentSSAIDSelection2.getSsaUserId()));
Iterator<AuditLogEntry> auditLogEntrys = logList.iterator();
int i = 0;
while (auditLogEntrys.hasNext())
{
final AuditLogEntry auditLogEntry = auditLogEntrys.next();
Row row = sheet.createRow(i);
row.createCell(0).setCellValue(auditLogEntry.getTimeStamp());
row.createCell(1).setCellValue(auditLogEntry.getSourceName());
row.createCell(2).setCellValue(auditLogEntry.getCategory());
row.createCell(3).setCellValue(auditLogEntry.getSsaAdmin());
row.createCell(4).setCellValue(auditLogEntry.getAction());
i++;
}
try
{
FileOutputStream output = new FileOutputStream("ssaUserIDAccess.xls");
workbook.write(output);
output.close();
}catch(Exception e)
{
e.printStackTrace();
}
}
You would have to create a DownloadLink with the temporary file as input. The temporary File must be deleted after download (file.delete())).
Alternatively you can try this:
IResourceStream stream = new ByteArrayResourceStream(data, "application/vnd.ms-excel");
RequestCycle.get().scheduleRequestHandlerAfterCurrent(new ResourceStreamRequestHandler(stream, filename).setContentDisposition(ContentDisposition.ATTACHMENT));
In this case data is the byte[] content of your workbook which can be for example retrieved with output.toByteArray().
In case anyone runs into this problem here is my solution. There wasn't a lot of straight forward answers on this but this is my solution:
My excelCreator method handles the creation of the excel Sheet, and returns it as a file.
private File excelCreator()
{
Workbook workbook = new HSSFWorkbook();
File excelfile = new File("userIDAccess.xls");
logList = getServer().findAuditLogs(getUserId(), null);
Sheet sheet = workbook.createSheet(WorkbookUtil.createSafeSheetName("User ID " + getUserId()));
Iterator<AuditLogEntry> auditLogEntrys = logList.iterator();
int i = 0;
while (auditLogEntrys.hasNext())
{
final AuditLogEntry auditLogEntry = auditLogEntrys.next();
Row row = sheet.createRow(i);
row.createCell(0).setCellValue(auditLogEntry.getTimeStamp());
row.createCell(1).setCellValue(auditLogEntry.getSourceName());
row.createCell(2).setCellValue(auditLogEntry.getCategory());
row.createCell(3).setCellValue(auditLogEntry.getSsaAdmin());
row.createCell(4).setCellValue(auditLogEntry.getAction());
i++;
}
try
{
FileOutputStream output = new FileOutputStream(excelfile);
workbook.write(output);
output.close();
}catch(Exception e)
{
e.printStackTrace();
}
return excelfile;
}
IModel excelFileModel = new AbstractReadOnlyModel()
{
public Object getObject()
{
return excelCreator();
}
};
I created an IModel to capture the file created inside my excelCreator() method and returned.
auditDownloadlink = new DownloadLink("auditDownloadlink", excelFileModel);
I pass the I.D. of the download link, and then pass the imodel.
finally,
I call,
auditDownloadlink.setDeleteAfterDownload(true);
auditDownloadlink.setCacheDuration(Duration.NONE);
This deletes the file after it is created. And the cache setting is a setting to make sure it is compatible with all browsers (That's how I interpreted it, but you may not need it).
The Imodel creates the File on the fly so it doesn't have to be stored anywhere, and then the file is deleted once it is downloaded.
Hope this helps someone!
You could create a Resource to do this, and make a ResourceLink.
public class ExcelProducerResource extends AbstractResource
{
public ExcelProducerResource()
{
}
#Override
protected ResourceResponse newResourceResponse( Attributes attributes )
{
final String fileName = getFileName();
ResourceResponse resourceResponse = new ResourceResponse();
resourceResponse.setContentType( "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" );
resourceResponse.setCacheDuration( Duration.NONE );
resourceResponse.setFileName( fileName );
resourceResponse.setWriteCallback( new WriteCallback()
{
#Override
public void writeData( Attributes attributes ) throws IOException
{
OutputStream outputStream = attributes.getResponse().getOutputStream();
writeToStream( outputStream );
outputStream.close();
}
} );
return resourceResponse;
}
void writeToStream(OutputStream outputStream) throws IOException
{
//.. do stuff here :)
}
String getFileName()
{
//.. do stuff here :)
}
}

Resources