diff --git a/pom.xml b/pom.xml index e5d1a1b..33f8cc5 100644 --- a/pom.xml +++ b/pom.xml @@ -107,6 +107,11 @@ pdf-renderer 1.0.5 + + org.apache.pdfbox + pdfbox + 1.8.3 + commons-fileupload commons-fileupload diff --git a/src/main/java/org/gcube/portlets/user/shareupdates/client/view/ShareUpdateForm.java b/src/main/java/org/gcube/portlets/user/shareupdates/client/view/ShareUpdateForm.java index 5cbdb14..89d4a90 100644 --- a/src/main/java/org/gcube/portlets/user/shareupdates/client/view/ShareUpdateForm.java +++ b/src/main/java/org/gcube/portlets/user/shareupdates/client/view/ShareUpdateForm.java @@ -180,8 +180,7 @@ public class ShareUpdateForm extends Composite { FileUpload up = uploadProgress.initialize(); up.setVisible(false); fileBrowse(up.getElement()); - uploadProgress.setVisible(true); - attachButton.getElement().getStyle().setVisibility(Visibility.HIDDEN); //beacuse otherwise it looses the other properties setting + uploadProgress.setVisible(true); } else { Window.alert("You cannot post two files, please remove the previous one first."); } @@ -196,7 +195,8 @@ public class ShareUpdateForm extends Composite { @UiHandler("submitButton") - void onClick(ClickEvent e) { + void onClick(ClickEvent e) { + attachButton.getElement().getStyle().setVisibility(Visibility.VISIBLE); //beacuse otherwise it looses the other properties setting shareupdateService.getUserSettings(new AsyncCallback() { public void onFailure(Throwable caught) { Window.alert("Ops! we encountered some problems delivering your message, server is not responding, please try again in a short while."); @@ -366,7 +366,8 @@ public class ShareUpdateForm extends Composite { preview.clear(); uploadProgress.setVisible(false); if (result != null) - addPreview(result, true); + addPreview(result, true); + attachButton.getElement().getStyle().setVisibility(Visibility.HIDDEN); //beacuse otherwise it looses the other properties setting } }); } diff --git a/src/main/java/org/gcube/portlets/user/shareupdates/server/FilePreviewer.java b/src/main/java/org/gcube/portlets/user/shareupdates/server/FilePreviewer.java index b253427..0ecf437 100644 --- a/src/main/java/org/gcube/portlets/user/shareupdates/server/FilePreviewer.java +++ b/src/main/java/org/gcube/portlets/user/shareupdates/server/FilePreviewer.java @@ -1,5 +1,129 @@ package org.gcube.portlets.user.shareupdates.server; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; + +import javax.imageio.ImageIO; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.util.PDFTextStripper; +import org.gcube.applicationsupportlayer.social.storage.FTPManager; +import org.gcube.portal.databook.shared.ImageType; +import org.gcube.portlets.user.shareupdates.shared.LinkPreview; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.pdfview.PDFFile; +import com.sun.pdfview.PDFPage; +import com.sun.pdfview.PDFParseException; +/** + * + * @author Massimiliano Assante, ISTI-CNR + * + * Parse files and returns an image preview plus description + * + */ public class FilePreviewer { + private static Logger _log = LoggerFactory.getLogger(FilePreviewer.class); + + private static final String PDF_DEFAULT_IMAGE = "default_pdf.png"; + + private static FTPManager getFTPManager() { + return FTPManager.getInstance(); + } + /** + * + * @param fileName thename of the file + * @param path2Pdf the path of the pdf file + * @param httpUrl the http url where the file is reachable at + * @return + * @throws Exception + */ + protected static LinkPreview getPdfPreview(String fileName, String path2Pdf, String httpUrl) throws Exception { + ArrayList imagesUrl = new ArrayList(); + //description + String desc = null; + try { + desc = getPDFDescription(path2Pdf); + } + catch (Exception ex) { + _log.warn("PDF Parse exception, returning no description"); + desc = ""; + } + //thumbnail preview + File pdfFile = new File(path2Pdf); + RandomAccessFile raf = new RandomAccessFile(pdfFile, "r"); + FileChannel channel = raf.getChannel(); + ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); + PDFFile pdf = null; + try { + pdf = new PDFFile(buf); + } catch (PDFParseException ex) { + raf.close(); + _log.error("PDF Parse exception, returning default pdf image"); + + imagesUrl.add(getFTPManager().getBaseURL()+PDF_DEFAULT_IMAGE); + return new LinkPreview(fileName, desc, httpUrl, "d4science.org", imagesUrl); + } + PDFPage page = pdf.getPage(0); + + int width = (int) page.getBBox().getWidth(); + int height = (int) page.getBBox().getHeight(); + + int scaledWidth = width/8; + int scaledHeight = height/8; + + // create the image + Rectangle rect = new Rectangle(0, 0, width, height); + + BufferedImage bufferedImage = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB); + + Image image = page.getImage(scaledWidth, scaledHeight, rect, null, true, true); + + Graphics2D bufImageGraphics = bufferedImage.createGraphics(); + bufImageGraphics.drawImage(image, 0, 0, scaledWidth, scaledHeight, null); + + //thumbnail previes are very small in this case we can use in-memory streams + ByteArrayOutputStream out = new ByteArrayOutputStream(); + boolean result = ImageIO.write(bufferedImage, "JPG", out); + raf.close(); + + if (result) { + String httpLink = getFTPManager().uploadImageOnFTPServer(new ByteArrayInputStream(out.toByteArray()), ImageType.JPG); + _log.debug("PDF thumbnail available at: " + httpLink); + imagesUrl.add(httpLink); + return new LinkPreview(fileName, desc, httpUrl, "d4science.org", imagesUrl); + } + else + throw new IOException("Could not process pdf file"); + } + + /** + * + * @param path2File + * @return + * @throws Exception + */ + private static String getPDFDescription(String path2File) throws Exception { + PDDocument doc = PDDocument.load(path2File); + PDFTextStripper stripper = new PDFTextStripper(); + //only first page text + stripper.setStartPage(1); + stripper.setEndPage(1); + String text = stripper.getText(doc); + String toReturn = (text.length() > 300) ? text.substring(0, 295) + " ... " : text; + doc.close(); + return toReturn; + } } diff --git a/src/main/java/org/gcube/portlets/user/shareupdates/server/ShareUpdateServiceImpl.java b/src/main/java/org/gcube/portlets/user/shareupdates/server/ShareUpdateServiceImpl.java index 79dbf4f..5be18c4 100644 --- a/src/main/java/org/gcube/portlets/user/shareupdates/server/ShareUpdateServiceImpl.java +++ b/src/main/java/org/gcube/portlets/user/shareupdates/server/ShareUpdateServiceImpl.java @@ -1,28 +1,17 @@ package org.gcube.portlets.user.shareupdates.server; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Rectangle; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.UUID; -import javax.imageio.ImageIO; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; @@ -33,14 +22,21 @@ import org.gcube.application.framework.core.session.ASLSession; import org.gcube.application.framework.core.session.SessionManager; import org.gcube.applicationsupportlayer.social.ApplicationNotificationsManager; import org.gcube.applicationsupportlayer.social.NotificationsManager; -import org.gcube.applicationsupportlayer.social.ftp.FTPManager; +import org.gcube.applicationsupportlayer.social.storage.FTPManager; +import org.gcube.applicationsupportlayer.social.storage.UriResolverReaderParameter; import org.gcube.common.homelibrary.home.HomeLibrary; import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException; import org.gcube.common.homelibrary.home.exceptions.InternalErrorException; import org.gcube.common.homelibrary.home.workspace.Workspace; import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException; +import org.gcube.common.portal.PortalContext; +import org.gcube.common.scope.api.ScopeProvider; import org.gcube.common.scope.impl.ScopeBean; import org.gcube.common.scope.impl.ScopeBean.Type; +import org.gcube.contentmanagement.blobstorage.service.IClient; +import org.gcube.contentmanager.storageclient.wrapper.AccessType; +import org.gcube.contentmanager.storageclient.wrapper.MemoryType; +import org.gcube.contentmanager.storageclient.wrapper.StorageClient; import org.gcube.portal.custom.communitymanager.OrganizationsUtil; import org.gcube.portal.custom.scopemanager.scopehelper.ScopeHelper; import org.gcube.portal.databook.client.GCubeSocialNetworking; @@ -49,16 +45,15 @@ import org.gcube.portal.databook.server.DatabookStore; import org.gcube.portal.databook.shared.ClientFeed; import org.gcube.portal.databook.shared.Feed; import org.gcube.portal.databook.shared.FeedType; -import org.gcube.portal.databook.shared.ImageType; import org.gcube.portal.databook.shared.PrivacyLevel; import org.gcube.portal.databook.shared.UserInfo; import org.gcube.portal.databook.shared.ex.FeedIDNotFoundException; -import org.gcube.portlets.widgets.pickuser.shared.PickingUser; import org.gcube.portlets.user.shareupdates.client.ShareUpdateService; import org.gcube.portlets.user.shareupdates.server.metaseeker.MetaSeeker; import org.gcube.portlets.user.shareupdates.server.opengraph.OpenGraph; import org.gcube.portlets.user.shareupdates.shared.LinkPreview; import org.gcube.portlets.user.shareupdates.shared.UserSettings; +import org.gcube.portlets.widgets.pickuser.shared.PickingUser; import org.gcube.vomanagement.usermanagement.GroupManager; import org.gcube.vomanagement.usermanagement.UserManager; import org.gcube.vomanagement.usermanagement.impl.liferay.LiferayGroupManager; @@ -82,9 +77,6 @@ import com.liferay.portal.service.OrganizationLocalServiceUtil; import com.liferay.portal.service.UserLocalServiceUtil; import com.liferay.portal.theme.ThemeDisplay; import com.sun.net.ssl.HttpsURLConnection; -import com.sun.pdfview.PDFFile; -import com.sun.pdfview.PDFPage; -import com.sun.pdfview.PDFParseException; /** * The server side implementation of the RPC service. @@ -98,16 +90,20 @@ public class ShareUpdateServiceImpl extends RemoteServiceServlet implements Shar /** * */ - private static final String PDF_DEFAULT_IMAGE = "default_pdf.png"; + + private static final String STORAGE_OWNER = "gCubeSocialFramework"; + public static final String UPLOAD_DIR = "/social-framework-uploads"; /** * */ private static Logger _log = LoggerFactory.getLogger(ShareUpdateServiceImpl.class); /** - * The store interface + * The Cassandra store interface */ private DatabookStore store; - + /** + * the FTP Storage + */ private FTPManager ftpStore; /** * used for debugging in eclipse @@ -118,7 +114,7 @@ public class ShareUpdateServiceImpl extends RemoteServiceServlet implements Shar */ public void init() { store = new DBCassandraAstyanaxImpl(); - ftpStore = FTPManager.getManager(); + ftpStore = FTPManager.getInstance(); } public void destroy() { @@ -337,66 +333,45 @@ public class ShareUpdateServiceImpl extends RemoteServiceServlet implements Shar */ @Override public LinkPreview checkUploadedFile(String fileName, String fileabsolutePathOnServer) { - String imageUrl = null; + LinkPreview toReturn = null; + + String randomUploadFolderName = UUID.randomUUID().toString(); + String remoteFilePath = UPLOAD_DIR + "/" + randomUploadFolderName + "/" + fileName; + + String currScope = ScopeProvider.instance.get(); + ScopeProvider.instance.set("/"+PortalContext.getConfiguration().getInfrastructureName()); + IClient storageClient = new StorageClient(STORAGE_OWNER, AccessType.SHARED, MemoryType.PERSISTENT).getClient(); + ScopeProvider.instance.set(currScope); + + + + String httpURL = ""; + + String smpURI = storageClient.getUrl().RFile(remoteFilePath); + + //The uploader Thread starts here asyncronously + Thread thread = new Thread(new UploadToStorageThread(storageClient, fileName, fileabsolutePathOnServer, remoteFilePath)); + thread.start(); + try { - imageUrl = getPdfPreviewImage(fileabsolutePathOnServer); + UriResolverReaderParameter resolver = new UriResolverReaderParameter(); + //get the url to show (though it could not be ready for download at this stage) + httpURL = resolver.resolveAsUriRequest(smpURI, fileName, "application/pdf", true); + + //TODO: switch + toReturn = FilePreviewer.getPdfPreview(fileName, fileabsolutePathOnServer, httpURL); } catch (Exception e) { + _log.error("Error while resolving or previewing file"); e.printStackTrace(); - } - ArrayList imagesUrl = new ArrayList(); - imagesUrl.add(imageUrl); - return new LinkPreview(fileName, "the Desc", "http://www.lalala.com", "d4science.org", imagesUrl); - } - - - private String getPdfPreviewImage(String path2Pdf) throws Exception { - File pdfFile = new File(path2Pdf); - RandomAccessFile raf = new RandomAccessFile(pdfFile, "r"); - FileChannel channel = raf.getChannel(); - ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); - PDFFile pdf = null; - try { - pdf = new PDFFile(buf); - } catch (PDFParseException ex) { - raf.close(); - _log.error("PDF Parse exception, returning default pdf image"); - return ftpStore.getBaseURL()+PDF_DEFAULT_IMAGE; - } - PDFPage page = pdf.getPage(0); + } - int width = (int) page.getBBox().getWidth(); - int height = (int) page.getBBox().getHeight(); - - int scaledWidth = width/8; - int scaledHeight = height/8; - - // create the image - Rectangle rect = new Rectangle(0, 0, width, height); - - BufferedImage bufferedImage = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB); - - Image image = page.getImage(scaledWidth, scaledHeight, // width & height - rect, // clip rect - null, // null for the ImageObserver - true, // fill background with white - true // block until drawing is done - ); - Graphics2D bufImageGraphics = bufferedImage.createGraphics(); - bufImageGraphics.drawImage(image, 0, 0, scaledWidth, scaledHeight, null); - - //images are very small in this case we can use in-memory streams - ByteArrayOutputStream out = new ByteArrayOutputStream(); - boolean result = ImageIO.write(bufferedImage, "JPG", out); - raf.close(); - - if (result) { - String httpLink = ftpStore.uploadImageOnFTPServer(new ByteArrayInputStream(out.toByteArray()), ImageType.JPG); - _log.debug("PDF thumbnail available at: " + httpLink); - return httpLink; - } - else - throw new IOException("Could not process pdf file"); + _log.debug("smpURI=" + smpURI); + _log.debug("Returning httpURL=" + httpURL); + return toReturn; } + + + /** * return the id as key and the names as value of the vre a user is subscribed to @@ -804,5 +779,5 @@ public class ShareUpdateServiceImpl extends RemoteServiceServlet implements Shar return workspace; } - + } diff --git a/src/main/java/org/gcube/portlets/user/shareupdates/server/UploadToStorageThread.java b/src/main/java/org/gcube/portlets/user/shareupdates/server/UploadToStorageThread.java new file mode 100644 index 0000000..803e9dc --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/shareupdates/server/UploadToStorageThread.java @@ -0,0 +1,48 @@ +package org.gcube.portlets.user.shareupdates.server; + +import org.gcube.contentmanagement.blobstorage.service.IClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author Massimiliano Assante ISTI-CNR + * + */ +public class UploadToStorageThread implements Runnable { + private static Logger _log = LoggerFactory.getLogger(UploadToStorageThread.class); + + /** + * remote path (with file name) in which you want to put the file + */ + private String remoteFilePath; + /** + * the name of the file you are putting + */ + private String fileName; + /** + * the path (with name) of the file you are putting + */ + private String fileabsolutePathOnServer; + + private IClient sClient; + /** + * + * @param sClient the instance of the storage client + * @param fileToUpload the absolute path of the file + */ + public UploadToStorageThread(IClient sClient, String fileName, String fileabsolutePathOnServer, String remoteFilePath) { + super(); + this.sClient = sClient; + this.remoteFilePath = remoteFilePath; + this.fileName = fileName; + this.fileabsolutePathOnServer = fileabsolutePathOnServer; + } + + @Override + public void run() { + String theID = sClient.put(true).LFile(fileabsolutePathOnServer).RFile(remoteFilePath); + _log.debug("Uploaded " + fileName + " - Returned Storage id=" + theID); + } + +} diff --git a/src/main/resources/clientlog4j.properties b/src/main/resources/clientlog4j.properties index 2248fe1..fd367a5 100644 --- a/src/main/resources/clientlog4j.properties +++ b/src/main/resources/clientlog4j.properties @@ -15,3 +15,4 @@ log4j.logger.org.gcube.resources.discovery.icclient=ERROR log4j.logger.org.gcube.common.clients=ERROR log4j.logger.org.gcube.common.homelibrary.jcr=ERROR log4j.logger.org.gcube.application.framework.accesslogger=ERROR +log4j.logger.org.apache.pdfbox.util.PDFStreamEngine=ERROR