package org.exoplatform.wcm.connector.collaboration;
import org.apache.commons.lang.StringUtils;
import org.apache.tika.io.IOUtils;
import org.exoplatform.services.cms.documents.DocumentTypeService;
import org.exoplatform.services.cms.documents.impl.DocumentType;
import org.exoplatform.services.cms.link.LinkManager;
import org.exoplatform.services.cms.link.NodeFinder;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.resources.ResourceBundleService;
import org.exoplatform.services.rest.resource.ResourceContainer;
import org.exoplatform.services.wcm.core.NodetypeConstant;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
import org.json.JSONObject;
import org.picocontainer.Startable;
import javax.annotation.security.RolesAllowed;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import java.net.URLDecoder;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
* Created by The eXo Platform SAS
* Author : eXoPlatform
* toannh@exoplatform.com
* Dec 09, 2014
* Provider all rest methods of Open Document feature.
*/
@Path("/office/")
@RolesAllowed("users")
public class OpenInOfficeConnector implements ResourceContainer, Startable {
private Log log = ExoLogger.getExoLogger(OpenInOfficeConnector.class);
private final String OPEN_DOCUMENT_ON_DESKTOP_ICO = "uiIconOpenOnDesktop";
private final String CONNECTOR_BUNDLE_LOCATION = "locale.wcm.resources.WCMResourceBundleConnector";
private final String OPEN_DOCUMENT_ON_DESKTOP_RESOURCE_KEY = "OpenInOfficeConnector.label.exo.remote-edit.desktop";
private final String OPEN_DOCUMENT_IN_DESKTOP_APP_RESOURCE_KEY = "OpenInOfficeConnector.label.exo.remote-edit.desktop-app";
private final String OPEN_DOCUMENT_DEFAULT_TITLE = "Open on Desktop";
private final int CACHED_TIME = 60*24*30*12;
private static final String VERSION_MIXIN ="mix:versionable";
private NodeFinder nodeFinder;
private LinkManager linkManager;
private ResourceBundleService resourceBundleService;
private DocumentTypeService documentTypeService;
public OpenInOfficeConnector(NodeFinder nodeFinder,
LinkManager linkManager,
ResourceBundleService resourceBundleService,
DocumentTypeService documentTypeService){
this.nodeFinder = nodeFinder;
this.linkManager = linkManager;
this.resourceBundleService = resourceBundleService;
this.documentTypeService = documentTypeService;
}
/**
* Return a JsonObject's current file to update display titles
* @param request
* @param objId
* @return
* @throws Exception
*/
@GET
@Path("/updateDocumentTitle")
public Response updateDocumentTitle(
@Context Request request,
@QueryParam("objId") String objId,
@QueryParam("lang") String language) throws Exception {
//find from cached
objId = URLDecoder.decode(objId, "UTF-8");
String[] nodeInfo = objId.split(":");
String workspace = nodeInfo[0];
String filePath = nodeInfo[1];
String extension = filePath.substring(filePath.lastIndexOf(".") + 1, filePath.length());
if(extension.contains("[")) extension=extension.substring(0, extension.indexOf("["));
EntityTag etag = new EntityTag(Integer.toString((extension+"_"+language).hashCode()));
Response.ResponseBuilder builder = request.evaluatePreconditions(etag);
if(builder!=null) return builder.build();
//query form configuration values params
CacheControl cc = new CacheControl();
cc.setMaxAge(CACHED_TIME);
ResourceBundle resourceBundle = resourceBundleService.getResourceBundle(CONNECTOR_BUNDLE_LOCATION, new Locale(language));
String title = resourceBundle!=null?resourceBundle.getString(OPEN_DOCUMENT_ON_DESKTOP_RESOURCE_KEY):OPEN_DOCUMENT_DEFAULT_TITLE;
String ico = OPEN_DOCUMENT_ON_DESKTOP_ICO;
DocumentType documentType = documentTypeService.getDocumentType(extension);
if(documentType !=null && resourceBundle !=null ){
try {
if(!StringUtils.isEmpty(resourceBundle.getString(documentType.getResourceBundleKey())))
title = resourceBundle.getString(documentType.getResourceBundleKey());
}catch(MissingResourceException ex){
String _openonDesktop = resourceBundle.getString(OPEN_DOCUMENT_IN_DESKTOP_APP_RESOURCE_KEY);
if(_openonDesktop!=null && _openonDesktop.contains("{0}")) {
title = _openonDesktop.replace("{0}", documentType.getResourceBundleKey());
}else{
title = OPEN_DOCUMENT_DEFAULT_TITLE;
}
}
if(!StringUtils.isEmpty(documentType.getIconClass())) ico=documentType.getIconClass();
}
Node node;
String nodePath = filePath;
boolean isFile=false;
try{
node = (Node)nodeFinder.getItem(workspace, filePath);
if (linkManager.isLink(node)) node = linkManager.getTarget(node);
nodePath = node.getPath();
isFile = node.isNodeType(NodetypeConstant.NT_FILE);
}catch(RepositoryException ex){
if(log.isErrorEnabled()){log.error("Exception when get node with path: "+filePath, ex);}
}
boolean isMsoffice = false;
if (documentType.getResourceBundleKey() != OPEN_DOCUMENT_ON_DESKTOP_RESOURCE_KEY) {
isMsoffice = true;
}
JSONObject rs = new JSONObject();
rs.put("ico", ico);
rs.put("title", title);
rs.put("repository", WCMCoreUtils.getRepository().getConfiguration().getName());
rs.put("workspace", workspace);
rs.put("filePath", nodePath);
rs.put("isFile", isFile);
rs.put("isMsoffice", isMsoffice);
builder = Response.ok(rs.toString(), MediaType.APPLICATION_JSON);
builder.tag(etag);
builder.cacheControl(cc);
return builder.build();
}
/**
* Get Title, css class of document by document's name
* @param fileName
* @return
*/
public String[] getDocumentInfos(String fileName){
String title = OPEN_DOCUMENT_ON_DESKTOP_RESOURCE_KEY;
String icon = OPEN_DOCUMENT_ON_DESKTOP_ICO;
String _extension = "";
if(fileName.lastIndexOf(".") > 0 ) {
_extension = StringUtils.substring(fileName, fileName.lastIndexOf(".") + 1, fileName.length());
}
if(StringUtils.isBlank(_extension)) return new String[]{title, icon};
DocumentType documentType = documentTypeService.getDocumentType(_extension);
if(documentType !=null){
if(!StringUtils.isEmpty(documentType.getResourceBundleKey())) title=documentType.getResourceBundleKey();
if(!StringUtils.isEmpty(documentType.getIconClass())) icon=documentType.getIconClass();
}
return new String[]{title, icon};
}
/**
* Return a JsonObject's check a version when file has been opened successfully by desktop application
* @param request
* @param filePath
* @return
* @throws Exception
*/
@GET
@Path("/checkout")
public Response checkout(@Context Request request,
@QueryParam("filePath") String filePath,
@QueryParam("workspace") String workspace
) throws Exception {
Session session = WCMCoreUtils.getSystemSessionProvider().
getSession(workspace, WCMCoreUtils.getRepository());
Node node = (Node)session.getItem(filePath);
if(node.canAddMixin(VERSION_MIXIN)){
node.addMixin(VERSION_MIXIN);
node.save();
node.checkin();
node.checkout();
}
if(!node.isCheckedOut()) node.checkout();
return Response.ok(String.valueOf(node.isCheckedOut()), MediaType.TEXT_PLAIN).build();
}
/**
* Return a a input stream internet shortcut to open file with desktop application
* @param httpServletRequest
* @param filePath
* @return
* @throws Exception
*/
@GET
@Path("/{linkFilePath}/")
@Produces("application/internet-shortcut")
public Response createShortcut(@Context HttpServletRequest httpServletRequest,
@PathParam("linkFilePath") String linkFilePath,
@QueryParam("filePath") String filePath,
@QueryParam("workspace") String workspace
) throws Exception {
Session session = WCMCoreUtils.getSystemSessionProvider().getSession(workspace, WCMCoreUtils.getRepository());
Node node = (Node)session.getItem(filePath);
String repo = WCMCoreUtils.getRepository().getConfiguration().getName();
String obsPath = httpServletRequest.getScheme()+ "://" + httpServletRequest.getServerName() + ":"
+httpServletRequest.getServerPort() + "/"
+ WCMCoreUtils.getRestContextName()+ "/private/jcr/" + repo + "/" + workspace + node.getPath();
String shortCutContent = "[InternetShortcut]\n";
shortCutContent+="URL="+obsPath+"\n";
return Response.ok(IOUtils.toInputStream(shortCutContent), MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition","attachment; filename="+node.getName()+".url")
.header("Content-type", "application/internet-shortcut")
.build();
}
@Override
public void start() {
}
@Override
public void stop() { }
}