/*
* Copyright (C) 2003-2007 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.ecm.webui.component.explorer.popup.admin;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.UUID;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.download.DownloadService;
import org.exoplatform.download.InputStreamDownloadResource;
import org.exoplatform.ecm.utils.text.Text;
import org.exoplatform.ecm.webui.component.explorer.UIJCRExplorer;
import org.exoplatform.ecm.webui.utils.Utils;
import org.exoplatform.services.compress.CompressData;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.web.application.ApplicationMessage;
import org.exoplatform.web.application.RequestContext;
import org.exoplatform.web.application.RequireJS;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.config.annotation.EventConfig;
import org.exoplatform.webui.core.UIApplication;
import org.exoplatform.webui.core.UIPopupComponent;
import org.exoplatform.webui.core.lifecycle.UIFormLifecycle;
import org.exoplatform.webui.core.model.SelectItemOption;
import org.exoplatform.webui.event.Event;
import org.exoplatform.webui.event.EventListener;
import org.exoplatform.webui.form.UIForm;
import org.exoplatform.webui.form.UIFormInputInfo;
import org.exoplatform.webui.form.UIFormRadioBoxInput;
import org.exoplatform.webui.form.input.UICheckBoxInput;
/**
* Created by The eXo Platform SARL
* Author : Dang Van Minh
* minh.dang@exoplatform.com
* Oct 5, 2006
*/
@ComponentConfig(
lifecycle = UIFormLifecycle.class,
template = "app:/groovy/webui/component/explorer/popup/admin/UIFormWithMultiRadioBox.gtmpl",
events = {
@EventConfig(listeners = UIExportNode.ExportActionListener.class),
@EventConfig(listeners = UIExportNode.ExportHistoryActionListener.class),
@EventConfig(listeners = UIExportNode.CancelActionListener.class)
}
)
public class UIExportNode extends UIForm implements UIPopupComponent {
private static final Log LOG = ExoLogger.getLogger(UIExportNode.class.getName());
public static final String NODE_PATH = "nodePath";
public static final String FORMAT = "format";
public static final String ZIP = "zip";
public static final String DOC_VIEW = "docview";
public static final String SYS_VIEW = "sysview";
public static final String VERSION_SQL_QUERY = "select * from mix:versionable where jcr:path like '$0/%' "
+ "order by exo:dateCreated DESC";
public static final String ROOT_SQL_QUERY = "select * from mix:versionable order by exo:dateCreated DESC";
private boolean isVerionNode_ = false;
public UIExportNode() throws Exception {
RequestContext context = RequestContext.getCurrentInstance();
ResourceBundle resourceBundle = context.getApplicationResourceBundle();
List<SelectItemOption<String>> formatItem = new ArrayList<SelectItemOption<String>>() ;
formatItem.add(new SelectItemOption<String>(
resourceBundle.getString("Import.label." + SYS_VIEW), SYS_VIEW));
formatItem.add(new SelectItemOption<String>(
resourceBundle.getString("Import.label." + DOC_VIEW), DOC_VIEW));
addUIFormInput(new UIFormInputInfo(NODE_PATH, NODE_PATH, null)) ;
addUIFormInput(new UIFormRadioBoxInput(FORMAT, SYS_VIEW, formatItem).
setAlign(UIFormRadioBoxInput.VERTICAL_ALIGN)) ;
addUIFormInput(new UICheckBoxInput(ZIP, ZIP, null)) ;
}
public void update(Node node) throws Exception {
getUIFormInputInfo(NODE_PATH).setValue(Text.unescapeIllegalJcrChars(node.getPath())) ;
}
public void activate() {
try {
update(getAncestorOfType(UIJCRExplorer.class).getCurrentNode());
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error("Unexpected error!", e.getMessage());
}
}
}
public void deActivate() { }
public QueryResult getQueryResult(Node currentNode) throws RepositoryException {
QueryManager queryManager = currentNode.getSession().getWorkspace().getQueryManager();
String queryStatement = "";
if(currentNode.getPath().equals("/")) {
queryStatement = ROOT_SQL_QUERY;
} else {
queryStatement = StringUtils.replace(VERSION_SQL_QUERY,"$0",currentNode.getPath());
}
Query query = queryManager.createQuery(queryStatement, Query.SQL);
return query.execute();
}
public String[] getActions() {
try {
Node currentNode = getAncestorOfType(UIJCRExplorer.class).getCurrentNode();
if(currentNode.isNodeType(Utils.MIX_VERSIONABLE)) isVerionNode_ = true;
QueryResult queryResult = getQueryResult(currentNode);
if(queryResult.getNodes().getSize() > 0 || isVerionNode_) {
return new String[] {"Export", "ExportHistory", "Cancel"};
}
} catch(Exception e) {
return new String[] {"Export", "Cancel"};
}
return new String[] {"Export", "Cancel"};
}
private String getHistoryValue(Node node) throws Exception {
String versionHistory = node.getProperty("jcr:versionHistory").getValue().getString();
String baseVersion = node.getProperty("jcr:baseVersion").getValue().getString();
Value[] predecessors = node.getProperty("jcr:predecessors").getValues();
StringBuilder historyValue = new StringBuilder();
StringBuilder predecessorsBuilder = new StringBuilder();
for(Value value : predecessors) {
if(predecessorsBuilder.length() > 0) predecessorsBuilder.append(",") ;
predecessorsBuilder.append(value.getString());
}
historyValue.append(node.getUUID()).append("=").append(versionHistory).
append(";").append(baseVersion).append(";").append(predecessorsBuilder.toString());
return historyValue.toString();
}
/**
* Create temp file to allow download a big data
* @return file
*/
private static File getExportedFile(String prefix, String suffix) throws IOException {
return File.createTempFile(prefix.concat(UUID.randomUUID().toString()), suffix);
}
static public class ExportActionListener extends EventListener<UIExportNode> {
public void execute(Event<UIExportNode> event) throws Exception {
UIExportNode uiExport = event.getSource();
UIJCRExplorer uiExplorer = uiExport.getAncestorOfType(UIJCRExplorer.class);
UIApplication uiApp = uiExport.getAncestorOfType(UIApplication.class);
File exportedFile = UIExportNode.getExportedFile("export", ".xml");
OutputStream out = new BufferedOutputStream(new FileOutputStream(exportedFile));
InputStream in = new BufferedInputStream(new TempFileInputStream(exportedFile));
CompressData zipService = new CompressData();
DownloadService dservice = uiExport.getApplicationComponent(DownloadService.class);
InputStreamDownloadResource dresource;
String format = uiExport.<UIFormRadioBoxInput> getUIInput(FORMAT).getValue();
boolean isZip = uiExport.getUICheckBoxInput(ZIP).isChecked();
Node currentNode = uiExplorer.getCurrentNode();
Session session = currentNode.getSession() ;
String nodePath = currentNode.getPath();
File zipFile = null;
try {
if(isZip) {
if (format.equals(DOC_VIEW))
session.exportDocumentView(nodePath, out, false, false);
else
session.exportSystemView(nodePath, out, false, false);
out.flush();
out.close();
zipFile = UIExportNode.getExportedFile("data", ".zip");
out = new BufferedOutputStream(new FileOutputStream(zipFile));
zipService.addInputStream(format + ".xml", in);
zipService.createZip(out);
in.close();
exportedFile.delete();
in = new BufferedInputStream(new TempFileInputStream(zipFile));
dresource = new InputStreamDownloadResource(in, "application/zip");
dresource.setDownloadName(format + ".zip");
} else {
if (format.equals(DOC_VIEW))
session.exportDocumentView(nodePath, out, false, false);
else
session.exportSystemView(nodePath, out, false, false);
out.flush();
dresource = new InputStreamDownloadResource(in, "text/xml");
dresource.setDownloadName(format + ".xml");
}
String downloadLink = dservice.getDownloadLink(dservice.addDownloadResource(dresource));
RequireJS requireJS = event.getRequestContext().getJavascriptManager().getRequireJS();
requireJS.require("SHARED/ecm-utils", "ecmutil").addScripts("ecmutil.ECMUtils.ajaxRedirect('" + downloadLink + "');");
uiExplorer.cancelAction();
} catch (OutOfMemoryError error) {
uiApp.addMessage(new ApplicationMessage("UIExportNode.msg.OutOfMemoryError", null, ApplicationMessage.ERROR));
return;
} finally {
out.close();
}
}
}
static public class ExportHistoryActionListener extends EventListener<UIExportNode> {
public void execute(Event<UIExportNode> event) throws Exception {
UIExportNode uiExport = event.getSource() ;
UIJCRExplorer uiExplorer = uiExport.getAncestorOfType(UIJCRExplorer.class) ;
UIApplication uiApp = uiExport.getAncestorOfType(UIApplication.class);
CompressData zipService = new CompressData();
DownloadService dservice = uiExport.getApplicationComponent(DownloadService.class) ;
InputStreamDownloadResource dresource ;
Node currentNode = uiExplorer.getCurrentNode();
String sysWsName = uiExplorer.getRepository().getConfiguration().getSystemWorkspaceName();
Session session = uiExplorer.getSessionByWorkspace(sysWsName);
QueryResult queryResult = uiExport.getQueryResult(currentNode);
NodeIterator queryIter = queryResult.getNodes();
String format = uiExport.<UIFormRadioBoxInput>getUIInput(FORMAT).getValue() ;
OutputStream out = null;
InputStream in = null;
List<File> lstExporedFile = new ArrayList<File>();
File exportedFile = null;
File zipFile = null;
File propertiesFile = UIExportNode.getExportedFile("mapping", ".properties");
OutputStream propertiesBOS = new BufferedOutputStream(new FileOutputStream(propertiesFile));
InputStream propertiesBIS = new BufferedInputStream(new TempFileInputStream(propertiesFile));
try {
while(queryIter.hasNext()) {
exportedFile = UIExportNode.getExportedFile("data", ".xml");
lstExporedFile.add(exportedFile);
out = new BufferedOutputStream(new FileOutputStream(exportedFile));
in = new BufferedInputStream(new TempFileInputStream(exportedFile));
Node node = queryIter.nextNode();
String historyValue = uiExport.getHistoryValue(node);
propertiesBOS.write(historyValue.getBytes());
propertiesBOS.write('\n');
if(format.equals(DOC_VIEW))
session.exportDocumentView(node.getVersionHistory().getPath(), out, false, false );
else
session.exportSystemView(node.getVersionHistory().getPath(), out, false, false );
out.flush();
zipService.addInputStream(node.getUUID() + ".xml", in);
}
if(currentNode.isNodeType(Utils.MIX_VERSIONABLE)) {
exportedFile = UIExportNode.getExportedFile("data", ".xml");
lstExporedFile.add(exportedFile);
out = new BufferedOutputStream(new FileOutputStream(exportedFile));
in = new BufferedInputStream(new TempFileInputStream(exportedFile));
String historyValue = uiExport.getHistoryValue(currentNode);
propertiesBOS.write(historyValue.getBytes());
propertiesBOS.write('\n');
if (format.equals(DOC_VIEW))
session.exportDocumentView(currentNode.getVersionHistory().getPath(), out, false, false);
else
session.exportSystemView(currentNode.getVersionHistory().getPath(), out, false, false);
out.flush();
zipService.addInputStream(currentNode.getUUID() + ".xml",in);
}
propertiesBOS.flush();
zipService.addInputStream("mapping.properties", propertiesBIS);
zipFile = UIExportNode.getExportedFile("data", "zip");
in = new BufferedInputStream(new TempFileInputStream(zipFile));
out = new BufferedOutputStream(new FileOutputStream(zipFile));
out.flush();
zipService.createZip(out);
dresource = new InputStreamDownloadResource(in, "application/zip") ;
dresource.setDownloadName(format + "_versionHistory.zip");
String downloadLink = dservice.getDownloadLink(dservice.addDownloadResource(dresource)) ;
RequireJS requireJS = event.getRequestContext().getJavascriptManager().getRequireJS();
requireJS.require("SHARED/ecm-utils", "ecmutil").addScripts("ecmutil.ECMUtils.ajaxRedirect('" + downloadLink + "');");
} catch (OutOfMemoryError error) {
uiApp.addMessage(new ApplicationMessage("UIExportNode.msg.OutOfMemoryError", null, ApplicationMessage.ERROR));
return;
} finally {
propertiesBOS.close();
propertiesBIS.close();
if (out != null) {
out.close();
}
}
}
}
static public class CancelActionListener extends EventListener<UIExportNode> {
public void execute(Event<UIExportNode> event) throws Exception {
UIJCRExplorer uiExplorer = event.getSource().getAncestorOfType(UIJCRExplorer.class) ;
uiExplorer.cancelAction() ;
}
}
private static class TempFileInputStream extends FileInputStream {
private final File file;
public TempFileInputStream(File file) throws FileNotFoundException {
super(file);
this.file = file;
try {
file.deleteOnExit();
} catch (Exception e) {
// ignore me
}
}
@Override
protected void finalize() throws IOException {
try {
file.delete();
} catch (Exception e) {
// ignore me
}
super.finalize();
}
}
}