/* ===============================================================================
*
* Part of the InfoGlue Content Management Platform (www.infoglue.org)
*
* ===============================================================================
*
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2, as published by the
* Free Software Foundation. See the file LICENSE.html for more information.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY, including 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, write to the Free Software Foundation, Inc. / 59 Temple
* Place, Suite 330 / Boston, MA 02111-1307 / USA.
*
* ===============================================================================
*/
/**
* @author Stefan Sik
* @since 1.4
*/
package org.infoglue.cms.applications.common.actions;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.infoglue.cms.applications.common.VisualFormatter;
import org.infoglue.cms.controllers.kernel.impl.simple.ContentController;
import org.infoglue.cms.controllers.kernel.impl.simple.ContentTypeDefinitionController;
import org.infoglue.cms.controllers.kernel.impl.simple.ContentVersionController;
import org.infoglue.cms.controllers.kernel.impl.simple.LanguageController;
import org.infoglue.cms.controllers.kernel.impl.simple.RepositoryController;
import org.infoglue.cms.controllers.kernel.impl.simple.TransactionHistoryController;
import org.infoglue.cms.entities.content.ContentVersionVO;
import org.infoglue.cms.entities.kernel.BaseEntityVO;
import org.infoglue.cms.entities.management.ContentTypeDefinitionVO;
import org.infoglue.cms.entities.management.RepositoryVO;
import org.infoglue.cms.entities.management.TransactionHistoryVO;
import org.infoglue.cms.entities.management.impl.simple.ContentTypeDefinitionImpl;
import org.infoglue.cms.exception.ConstraintException;
import org.infoglue.cms.exception.SystemException;
import org.infoglue.cms.security.InfoGluePrincipal;
import org.infoglue.cms.util.ChangeNotificationController;
import org.infoglue.cms.util.CmsPropertyHandler;
import org.infoglue.cms.util.XMLNotificationWriter;
import com.frovi.ss.Tree.BaseNode;
import com.frovi.ss.Tree.INodeSupplier;
public abstract class SimpleXmlServiceAction extends InfoGlueAbstractAction
{
private final static Logger logger = Logger.getLogger(SimpleXmlServiceAction.class.getName());
private static final String protectedPropertyFragments = "password,administrator,authorizer,authenticator,masterserver,slaveserver,log";
protected static final String SERVICEREVISION = "$Revision: 1.26 $";
protected static String ENCODING = "UTF-8";
protected static String TYPE_FOLDER = "Folder";
protected static String TYPE_ITEM = "Item";
protected static String TYPE_REPOSITORY = "Repository";
protected String showLeafs = "yes";
protected Integer parent = null;
protected Integer repositoryId = null;
protected String urlArgSeparator = "&";
protected String action = "";
protected boolean createAction = false;
protected boolean useTemplate = false;
protected VisualFormatter formatter = new VisualFormatter();
protected String[] allowedContentTypeIds = null;
private Integer sortLanguageId;
/*
*
* Experimental
*
*/
protected static Map changeNotificationBuffer = new HashMap();
public abstract INodeSupplier getNodeSupplier() throws SystemException;
protected abstract BaseEntityVO getRootEntityVO(Integer repositoryId, InfoGluePrincipal principal) throws ConstraintException, SystemException;
public List getContentTypeDefinitions() throws Exception
{
return ContentTypeDefinitionController.getController().getContentTypeDefinitionVOList();
}
public String encode(String text)
{
return text;
}
protected String makeAction(BaseNode node) throws UnsupportedEncodingException
{
String action = "javascript:onTreeItemClick(this,";
//action+="'" + node.getId() + "','" + repositoryId + "','" + URLEncoder.encode(node.getTitle(),ENCODING) + "');";
//action+="'" + node.getId() + "','" + repositoryId + "','" + new VisualFormatter().escapeForAdvancedJavascripts(node.getTitle()) + "');";
action+="'" + node.getId() + "','" + repositoryId + "','" + new VisualFormatter().escapeForAdvancedJavascripts(node.getTitle()) + "');";
return action;
}
protected String getFormattedDocument(Document doc)
{
return getFormattedDocument(doc, true, false);
}
protected String getFormattedDocument(Document doc, boolean compact, boolean supressDecl)
{
OutputFormat format = compact ? OutputFormat.createCompactFormat() : OutputFormat.createPrettyPrint();
format.setSuppressDeclaration(supressDecl);
format.setEncoding(ENCODING);
format.setExpandEmptyElements(false);
StringWriter stringWriter = new StringWriter();
XMLWriter writer = new XMLWriter(stringWriter, format);
try
{
writer.write(doc);
}
catch (IOException e)
{
e.printStackTrace();
}
return stringWriter.toString();
}
protected String out(String string) throws IOException
{
getResponse().setContentType("text/xml; charset=" + ENCODING);
getResponse().setHeader("Cache-Control","no-cache");
getResponse().setHeader("Pragma","no-cache");
getResponse().setDateHeader ("Expires", 0);
PrintWriter out = getResponse().getWriter();
out.println(string);
return NONE;
}
/*
* Returns all Languages for a given repository (repositoryId)
*/
public String doLanguage() throws Exception
{
return null;
}
public String doApplicationSettings() throws Exception
{
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement("applicationSettings");
Properties props = CmsPropertyHandler.getProperties();
for(Iterator i = props.keySet().iterator(); i.hasNext();)
{
String key = (String) i.next();
String elmKey = key;
if(key.matches("^\\d.*")) elmKey = "_" + key;
String value = (String) props.get(key);
if(!isProtectedProperty(key))
root.addElement(elmKey).setText(value);
}
root.addElement("serviceRevision").setText(SERVICEREVISION);
return out(getFormattedDocument(doc));
}
private boolean isProtectedProperty(String key)
{
String [] fragments = protectedPropertyFragments.split(",");
for(int i=0; i<fragments.length;i++)
if(key.toLowerCase().indexOf(fragments[i].toLowerCase()) > -1)
return true;
return false;
}
/*
* Returns all contentTypeDefinitions
*/
public String doContentTypeDefinitions() throws Exception
{
List contentTypeDefinitions = getContentTypeDefinitions();
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement("definitions");
TransactionHistoryController transactionHistoryController = TransactionHistoryController.getController();
for(Iterator i=contentTypeDefinitions.iterator();i.hasNext();)
{
ContentTypeDefinitionVO vo = (ContentTypeDefinitionVO) i.next();
if(vo.getType().compareTo(ContentTypeDefinitionVO.CONTENT)==0)
{
TransactionHistoryVO transactionHistoryVO = transactionHistoryController.getLatestTransactionHistoryVOForEntity(ContentTypeDefinitionImpl.class, vo.getContentTypeDefinitionId());
Element definition = DocumentHelper.createElement("definition");
definition
.addAttribute("id", "" + vo.getContentTypeDefinitionId())
.addAttribute("type", "" + vo.getType())
.addAttribute("name", vo.getName())
;
if(transactionHistoryVO!=null)
definition.addAttribute("mod", formatDate(transactionHistoryVO.getTransactionDateTime()));
Element schemaValue = definition.addElement("schemaValue");
schemaValue.addCDATA(vo.getSchemaValue());
root.add(definition);
}
}
return out(getFormattedDocument(doc));
}
public String doGetChangeNotifications() throws IOException
{
String id = getRequest().getSession().getId();
StringWriter buffer = (StringWriter) changeNotificationBuffer.get(id);
if(buffer==null)
{
buffer = new StringWriter();
buffer.write("<changeNotifications>");
changeNotificationBuffer.put(id, buffer);
XMLNotificationWriter streamWriter = new XMLNotificationWriter(buffer, ENCODING, "", null, true, true);
ChangeNotificationController.getInstance().registerListener(streamWriter);
}
buffer.write("</changeNotifications>");
try
{
out(getFormattedDocument(DocumentHelper.parseText(buffer.toString())));
}
catch(Exception e)
{
out("<exception/>");
}
buffer.getBuffer().delete(0, buffer.getBuffer().length());
buffer.write("<changeNotifications>");
return null;
}
public String doGetChangeNotificationsStream() throws IOException
{
boolean open = true;
String remoteId = getRequest().getRemoteAddr() + " / " + getInfoGluePrincipal().getName();
String boundary = getRequest().getParameter("boundary");
if(boundary==null) boundary = "-----------------infoglue-multipart-1d4faa3ac353573";
getResponse().setHeader("boundary", boundary);
getResponse().setBufferSize(0);
getResponse().setContentType("text/plain; charset=" + ENCODING);
getResponse().flushBuffer();
Thread thread = Thread.currentThread();
OutputStream out = getResponse().getOutputStream();
InputStream in = getRequest().getInputStream();
XMLNotificationWriter streamWriter = new XMLNotificationWriter(new OutputStreamWriter(out), ENCODING, boundary, thread, true, false);
logger.info("Notification stream listen started from:" + remoteId);
ChangeNotificationController.getInstance().registerListener(streamWriter);
Thread streamWriterThread = new Thread(streamWriter);
streamWriterThread.start();
while(open)
{
try
{
Thread.sleep(Long.MAX_VALUE);
out.flush();
}
catch (Exception e)
{
open = false;
}
}
ChangeNotificationController.getInstance().unregisterListener(streamWriter);
logger.info("Notification stream listen ended from:" + remoteId);
return null;
}
protected String formatDate(Date date)
{
return "" + date;
}
/*
* Main action, returns the content tree
*/
public String doExecute() throws Exception
{
if (useTemplate) return "success";
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement("tree");
INodeSupplier sup;
if(repositoryId == null)
{
List repositories = RepositoryController.getController().getAuthorizedRepositoryVOList(this.getInfoGluePrincipal(), false);
for(Iterator i=repositories.iterator();i.hasNext();)
{
RepositoryVO r = (RepositoryVO) i.next();
BaseEntityVO entityVO = getRootEntityVO(r.getId(), this.getInfoGluePrincipal());
String src= action + "?repositoryId=" + r.getId() + urlArgSeparator + (sortLanguageId != null ? "sortLanguageId=" + sortLanguageId : "") + urlArgSeparator + "parent=" + entityVO.getId();
if(createAction && src.length() >0) src += urlArgSeparator + "createAction=true";
if(action.length()>0 && src.length() >0) src += urlArgSeparator + "action=" + action;
String allowedContentTypeIdsUrlEncodedString = getAllowedContentTypeIdsAsUrlEncodedString();
logger.info("allowedContentTypeIdsUrlEncodedString1:" + allowedContentTypeIdsUrlEncodedString);
if(allowedContentTypeIdsUrlEncodedString.length()>0 && src.length() >0)
src += urlArgSeparator + allowedContentTypeIdsUrlEncodedString;
logger.info("src:" + src);
String text=r.getName();
Element element = root.addElement("tree");
element
.addAttribute("id", "" + r.getId())
.addAttribute("repositoryId", "" + r.getId())
.addAttribute("text", encode(text))
.addAttribute("src", src)
.addAttribute("hasChildren", "true")
.addAttribute("type", TYPE_REPOSITORY);
}
out(getFormattedDocument(doc));
return null;
}
sup = getNodeSupplier();
if(parent == null)
{
BaseNode node = sup.getRootNode();
String text = node.getTitle();
String type = TYPE_FOLDER;
String src = action + "?repositoryId=" + repositoryId + urlArgSeparator + (sortLanguageId != null ? "sortLanguageId=" + sortLanguageId : "") + urlArgSeparator + "parent=" + node.getId();
if(createAction && src.length() >0) src += urlArgSeparator + "createAction=true";
if(action.length()>0 && src.length() >0) src += urlArgSeparator + "action=" + action;
String allowedContentTypeIdsUrlEncodedString = getAllowedContentTypeIdsAsUrlEncodedString();
logger.info("allowedContentTypeIdsUrlEncodedString2:" + allowedContentTypeIdsUrlEncodedString);
if(allowedContentTypeIdsUrlEncodedString.length()>0 && src.length() >0)
src += urlArgSeparator + allowedContentTypeIdsUrlEncodedString;
//logger.info("src2:" + src);
Element elm = root.addElement("tree");
elm
.addAttribute("id", "" + node.getId())
.addAttribute("repositoryId", "" + repositoryId)
.addAttribute("text", encode(text))
.addAttribute("src", src)
.addAttribute("isLocalized", (String)node.getParameters().get("isLocalized"))
.addAttribute("isLanguageAvailable", (String)node.getParameters().get("isLanguageAvailable"))
.addAttribute("isHidden", (String)node.getParameters().get("isHidden"))
.addAttribute("hasChildren", "true")
.addAttribute("type", type);
if(node.getParameters().containsKey("contentTypeDefinitionId"))
elm.addAttribute("contentTypeDefinitionId", (String)node.getParameters().get("contentTypeDefinitionId"));
if(node.getParameters().containsKey("isProtected"))
elm.addAttribute("isProtected", (String)node.getParameters().get("isProtected"));
if(node.getParameters().containsKey("stateId"))
elm.addAttribute("stateId", (String)node.getParameters().get("stateId"));
out(getFormattedDocument(doc));
return null;
}
if(parent.intValue() > -1)
{
Collection containerNodes = sup.getChildContainerNodes(parent);
Collection childNodes = sup.getChildLeafNodes(parent);
ContentController contentController = ContentController.getContentController();
ContentVersionController contentVersionController = ContentVersionController.getContentVersionController();
Iterator it = containerNodes.iterator();
while (it.hasNext())
{
BaseNode theNode = (BaseNode) it.next();
if (theNode.isContainer() && sup.hasChildren())
{
theNode.setChildren(sup.hasChildren(theNode.getId()));
}
// String src = theNode.hasChildren() ? action + "?repositoryId=" + repositoryId + urlArgSeparator + "parent=" + theNode.getId(): "";
String src = action + "?repositoryId=" + repositoryId + urlArgSeparator + (sortLanguageId != null ? "sortLanguageId=" + sortLanguageId : "") + urlArgSeparator + "parent=" + theNode.getId();
if(createAction && src.length() >0) src += urlArgSeparator + "createAction=true";
if(createAction && src.length() >0) src += urlArgSeparator + "showLeafs=" + showLeafs;
if(action.length()>0 && src.length() >0) src += urlArgSeparator + "action=" + action;
String allowedContentTypeIdsUrlEncodedString = getAllowedContentTypeIdsAsUrlEncodedString();
if(allowedContentTypeIdsUrlEncodedString.length()>0 && src.length() >0) src += urlArgSeparator + allowedContentTypeIdsUrlEncodedString;
Element elm = root.addElement("tree");
elm
.addAttribute("id", "" + theNode.getId())
.addAttribute("parent", "" + parent)
.addAttribute("repositoryId", "" + repositoryId)
.addAttribute("text", encode(theNode.getTitle()))
.addAttribute("src", src)
.addAttribute("isLocalized", (String)theNode.getParameters().get("isLocalized"))
.addAttribute("isLanguageAvailable", (String)theNode.getParameters().get("isLanguageAvailable"))
.addAttribute("isHidden", (String)theNode.getParameters().get("isHidden"))
.addAttribute("type", TYPE_FOLDER)
.addAttribute("hasChildren", "" + theNode.hasChildren());
if(theNode.getParameters().containsKey("contentTypeDefinitionId"))
elm.addAttribute("contentTypeDefinitionId", "" + theNode.getParameters().get("contentTypeDefinitionId"));
if(theNode.getParameters().containsKey("isProtected"))
elm.addAttribute("isProtected", (String)theNode.getParameters().get("isProtected"));
if(theNode.getParameters().containsKey("stateId"))
elm.addAttribute("stateId", (String)theNode.getParameters().get("stateId"));
if(createAction) elm.addAttribute("action", makeAction(theNode));
}
it = childNodes.iterator();
while (it.hasNext())
{
BaseNode theNode = (BaseNode) it.next();
String text = theNode.getTitle();
String action = makeAction(theNode);
String type = TYPE_ITEM;
Element elm = root.addElement("tree");
elm
.addAttribute("id", "" + theNode.getId())
.addAttribute("parent", "" + parent)
.addAttribute("repositoryId", "" + repositoryId)
.addAttribute("text", encode(text))
.addAttribute("type", type)
;
if(theNode.getParameters().containsKey("contentTypeDefinitionId"))
elm.addAttribute("contentTypeDefinitionId", "" + theNode.getParameters().get("contentTypeDefinitionId"));
if(theNode.getParameters().containsKey("isProtected"))
elm.addAttribute("isProtected", (String)theNode.getParameters().get("isProtected"));
if(theNode.getParameters().containsKey("stateId"))
elm.addAttribute("stateId", (String)theNode.getParameters().get("stateId"));
if(createAction)
elm.addAttribute("action", action);
else
{
ContentVersionVO activeVersion = contentVersionController.getLatestActiveContentVersionVO(theNode.getId(), LanguageController.getController().getMasterLanguage(repositoryId).getLanguageId());
if(activeVersion!=null && !useTemplate)
{
elm.addAttribute("activeVersion", "" + activeVersion.getContentVersionId());
elm.addAttribute("activeVersionStateId", "" + activeVersion.getStateId());
elm.addAttribute("activeVersionModifier", "" + activeVersion.getVersionModifier());
}
}
//TODO - this was a quickfix only
if(!useTemplate && sup.getClass().getName().indexOf("Content") > -1)
{
if(theNode.getParameters().containsKey("contentTypeDefinitionId"))
elm.addAttribute("contentTypeId", "" + theNode.getParameters().get("contentTypeDefinitionId"));
else
{
try
{
ContentTypeDefinitionVO contentTypeDefinitionVO = contentController.getContentTypeDefinition(theNode.getId());
if(contentTypeDefinitionVO != null)
elm.addAttribute("contentTypeId","" + contentTypeDefinitionVO.getContentTypeDefinitionId());
}
catch (Exception e)
{
logger.error("The content " + theNode.getTitle() + " (" + theNode.getId() + " ) points to a removed content type perhaps: " + e.getMessage());
}
}
}
}
out(getFormattedDocument(doc));
return null;
}
return null;
}
public Integer getParent() {
return parent;
}
public void setParent(Integer integer) {
parent = integer;
}
public Integer getRepositoryId() {
return repositoryId;
}
public void setRepositoryId(Integer integer) {
repositoryId = integer;
}
public boolean isCreateAction()
{
return createAction;
}
public void setCreateAction(boolean createAction)
{
this.createAction = createAction;
}
public boolean isUseTemplate()
{
return useTemplate;
}
public void setUseTemplate(boolean useTemplate)
{
this.useTemplate = useTemplate;
}
public String getAction()
{
return action;
}
public void setAction(String action)
{
this.action = action;
}
public String getShowLeafs() {
return showLeafs;
}
public void setShowLeafs(String showLeafs) {
this.showLeafs = showLeafs;
}
public String[] getAllowedContentTypeIds()
{
return allowedContentTypeIds;
}
public void setAllowedContentTypeIds(String[] allowedContentTypeIds)
{
this.allowedContentTypeIds = allowedContentTypeIds;
}
public String getAllowedContentTypeIdsAsUrlEncodedString() throws Exception
{
if(allowedContentTypeIds == null)
return "";
StringBuffer sb = new StringBuffer();
for(int i=0; i<allowedContentTypeIds.length; i++)
{
if(i > 0)
sb.append("&");
sb.append("allowedContentTypeIds=" + URLEncoder.encode(allowedContentTypeIds[i], "UTF-8"));
}
return sb.toString();
}
public Integer getSortLanguageId()
{
return sortLanguageId;
}
public void setSortLanguageId(Integer sortLanguageId)
{
this.sortLanguageId = sortLanguageId;
}
}