package com.openedit.page;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openedit.Data;
import org.openedit.repository.ContentItem;
import org.openedit.repository.RepositoryException;
import com.openedit.Generator;
import com.openedit.OpenEditException;
import com.openedit.WebPageRequest;
import com.openedit.config.Script;
import com.openedit.config.Style;
import com.openedit.error.ContentNotAvailableException;
import com.openedit.generators.Output;
import com.openedit.util.FileUtils;
import com.openedit.util.OutputFiller;
import com.openedit.util.PathUtilities;
public class Page implements Data, Comparable
{
private static Log log = LogFactory.getLog(Page.class);
public static final String BLANK_LAYOUT = "NOLAYOUT";
protected String fieldPath;
protected PageSettings fieldPageSettings;
protected ContentItem fieldContentItem;
protected long fieldOriginalyModified;
protected Map fieldCache;
public Page( String inPath, PageSettings inMetaData )
{
fieldPath = inPath;
setPageSettings(inMetaData );
}
/**
*
*/
public Page()
{
}
public Page( Page inPage )
{
this( inPage.getPath(), inPage.getPageSettings() );
fieldContentItem = inPage.getContentItem();
}
protected Map getCache()
{
if( fieldCache == null)
{
fieldCache = new HashMap();
}
return fieldCache;
}
public boolean isBinary()
{
if ( getMimeType() == null)
{
return false; //There are many more text formats we support
}
if( getMimeType().startsWith("text") )
{
return false;
}
if( getMimeType().indexOf("xml") > -1 )
{
return false;
}
return true;
}
public boolean isFolder()
{
return getContentItem().isFolder();
}
public boolean exists()
{
return getContentItem().exists();
}
public Date getLastModified()
{
return getContentItem().lastModified();
}
public long lastModified()
{
return getContentItem().getLastModified();
}
/**
* This is asking if the settings have been changed under it
* @return
*/
public boolean isCurrent()
{
//Content
long time = getContentItem().getLastModified();
// if ( time == -1)
// {
// return false; //is missing. This seems very wasteful
// }
boolean pageCurrent = time == getOriginalyModified();
if( !pageCurrent)
{
return false;
}
boolean metaDataCurrent = getPageSettings().isCurrent();
return metaDataCurrent;
}
/**
* DOCME
*
* @param inDateFormat DOCME
*
* @return DOCME
*/
public String getLastModified(String inDateFormat)
{
Date date = getLastModified();
if( date == null)
{
return null;
}
SimpleDateFormat format = new SimpleDateFormat(inDateFormat);
return format.format(date);
}
/**
* DOCME
*
* @return DOCME
*/
public String getMimeType()
{
return getPageSettings().getMimeType();
}
/**
* Get a List of page actions. To add an action to the page just add the action to this List.
* Page actions are triggered each time the page is requested.
*
* @return A List of page actions
*/
public List getPageActions()
{
List copy = (List)getCache().get("pageActions");
if( copy == null)
{
List actions = getPageSettings().getPageActions();
if( isDynamic() )
{
copy = actions;
}
else
{
copy = new ArrayList(actions.size());
for (Iterator iter = actions.iterator(); iter.hasNext();)
{
PageAction action = (PageAction) iter.next();
if ( action.isIncludesAll() )
{
copy.add(action);
}
}
}
getCache().put("pageActions",copy);
}
return copy;
}
public List getStyles()
{
if( isHtml() )
{
List styles = getPageSettings().getStyles();
//look for duplicate
List copy = new ArrayList(styles.size());
Set got = new HashSet(styles.size());
for (Iterator iterator = styles.iterator(); iterator.hasNext();)
{
Style script = (Style) iterator.next();
if( !got.contains(script.getId()) )
{
copy.add(script);
got.add(script.getId()); //no duplicates
//script.setHref($content.getPageSettings().replaceProperty(script.getHref()));
}
}
return copy;
}
return null;
}
public List getScripts()
{
if( isHtml() )
{
List scripts = getPageSettings().getScripts();
//look for duplicate
List copy = new ArrayList(scripts.size());
HashMap ids = new HashMap(scripts.size());
for (Iterator iterator = scripts.iterator(); iterator.hasNext();)
{
Script script = (Script) iterator.next();
ids.put(script.getId(),script);
}
for (Iterator iterator = scripts.iterator(); iterator.hasNext();)
{
Script script = (Script) iterator.next();
Script goodone = (Script)ids.get(script.getId());
//goodone.setSrc(getPageSettings().replaceProperty(goodone.getSrc()));
if( !copy.contains(goodone) )
{
copy.add(goodone);
}
}
return copy;
}
return null;
}
public List getScriptPaths()
{
List paths = (List)getCache().get("scriptPaths");
if( paths == null)
{
List scripts = getScripts();
if( scripts != null)
{
paths = new ArrayList(scripts.size());
for (Iterator iterator = scripts.iterator(); iterator.hasNext();)
{
Script script = (Script) iterator.next();
paths.add(getPageSettings().replaceProperty(script.getSrc()));
}
getCache().put("scriptPaths",paths);
}
}
return paths;
}
public List getStylePaths()
{
List paths = (List)getCache().get("stylePaths");
if( paths == null)
{
List styles = getStyles();
if( styles != null)
{
paths = new ArrayList(styles.size());
for (Iterator iterator = styles.iterator(); iterator.hasNext();)
{
Style style = (Style) iterator.next();
paths.add(getPageSettings().replaceProperty(style.getHref()));
}
getCache().put("stylePaths",paths);
}
}
return paths;
}
/**
* Get a List of page actions. To add an action to the page just add the action to this List.
* Page actions are triggered each time the page is requested.
*
* @return A List of page actions
*/
public List getPathActions()
{
List copy = (List)getCache().get("pathActions");
if( copy == null)
{
List actions = getPageSettings().getPathActions();
if( isDynamic() )
{
copy = actions;
}
else
{
copy = new ArrayList(actions.size());
for (Iterator iter = actions.iterator(); iter.hasNext();)
{
PageAction action = (PageAction) iter.next();
if ( action.isIncludesAll() )
{
copy.add(action);
}
}
}
getCache().put("pathActions",copy);
}
return copy;
}
/**
* Get the request path.
*
* @return The request path
*/
public String getPath()
{
return fieldPath;
}
public String getDirectory()
{
String path = PathUtilities.extractDirectoryPath(getPath());
// urlpath is the address the link came in on
return path;
}
public String getDirectoryName()
{
String path = PathUtilities.extractDirectoryPath(getPath());
// urlpath is the address the link came in on
if( path.length()> 1)
{
path = PathUtilities.extractFileName(path);
}
return path;
}
public String getDirectoryRoot()
{
int slash = getPath().indexOf('/',1);
if( slash > 1)
{
return getPath().substring(0,slash);
}
// urlpath is the address the link came in on
return "";
}
public String getName()
{
String path = PathUtilities.extractFileName(getPath());
// urlpath is the address the link came in on
return path;
}
public String getPageName()
{
String path = PathUtilities.extractPageName(getPath());
return path;
}
public String getPageType()
{
String type = PathUtilities.extractPageType(getPath());
return type;
}
/**
* Get the named page property using the default Locale. If the property is not found then
* return null.
*
* @param name The property name
*
* @return The value or null
*/
public String getProperty(String name)
{
return getProperty(name, (Locale)null);
}
public String getProperty(String name, String language)
{
String val = null;
if( language != null )
{
PageProperty property = (PageProperty) getPageSettings().getProperty(name);
if (property != null)
{
val = property.getValue(language);
}
else
{
return null;
}
}
else
{
val = getProperty(name,(Locale)null );
}
val = getPageSettings().replaceProperty(val);
return val;
}
/**
* Get the Locale-specific value for the given named property. If the property is not found
* then return null. This method will try to find the most suitable locale by searching the
* property values in the following manner:
*
* <p>
* language + "_" + country + "_" + variant<br> language + "_" + country<br> langauge<br> ""
* </p>
*
* @param name The property name
* @param locale The locale
*
* @return The value
*/
public String getProperty(String name, Locale language)
{
if( log.isDebugEnabled())
{
debug("Get property [name=" + name + ",locale=" + language + "]");
}
PageProperty property = (PageProperty) getPageSettings().getProperty(name);
if (property != null)
{
String value = property.getValue(language);
value = getPageSettings().replaceProperty(value);
return value;
}
else
{
return null;
}
}
public void debug( String inMessage )
{
log.debug( inMessage );
//System.out.println( inMessage );
}
/**
* Get the named property. This method is equivilent to the <code>getProperty(name)</code>
* method. This method is provided as a convenience to Velocity code.
*
* @param name The property name
*
* @return The value
*/
public String get(String name)
{
if(name.equals("name")){
return getName();
}
if(name.equals("path")){
return getPath();
}
if(name.equals("id")){
return getId();
}
String value = getProperty(name);
//debug("get(" + name + ") called to retrieve property");
value = getPageSettings().replaceProperty(value);
return value;
}
public boolean isPropertyTrue(String inKey)
{
Object val = getProperty(inKey);
if( val != null)
{
return Boolean.parseBoolean(val.toString());
}
return false;
}
/**
* DOCME
*
* @return DOCME
*/
public String toString()
{
return getPath();
}
public void setPageSettings(PageSettings inSettings)
{
fieldPageSettings = inSettings;
}
public PageSettings getPageSettings()
{
return fieldPageSettings;
}
/**
* @return
*/
public String getAlternateContentPath()
{
return getPageSettings().getAlternateContentPath();
}
/**
* @return
*/
public List getGenerator()
{
return getPageSettings().getGenerators();
}
public InputStream getInputStream() throws ContentNotAvailableException
{
try
{
return getContentItem().getInputStream();
}
catch( RepositoryException e )
{
throw new ContentNotAvailableException(e.getMessage(), getPath() );
}
}
/**
* @return
*/
public String getLayout()
{
return getPageSettings().getLayout();
}
public String getInnerLayout()
{
PageSettings parent = getPageSettings();
return parent.getInnerLayoutExcludeSelf(getPath());
// while( parent != null)
// {
// String layout = parent.getInnerLayout();
// if( layout == null || !layout.equals(getPath()))
// {
// return layout;
// }
// parent = parent.getParent();
// }
// return null;
// }
}
public String findInnerLayout()
{
String il = getInnerLayout();
if ( il == null)
{
return null;
}
if ( il.equals(BLANK_LAYOUT))
{
return null;
}
if( il.equalsIgnoreCase(getPath()))
{
return null;
}
return il;
}
public boolean hasLayout()
{
String layout = getLayout();
return layout != null && !layout.equals(BLANK_LAYOUT);
}
public boolean hasInnerLayout()
{
String il = getInnerLayout();
if ( il == null)
{
return false;
}
if ( il.equals(BLANK_LAYOUT))
{
return false;
}
if( il.equalsIgnoreCase(getPath()))
{
return false;
}
return true;
}
public ContentItem getContentItem()
{
return fieldContentItem;
}
public void setContentItem( ContentItem revision )
{
fieldContentItem = revision;
if ( revision != null)
{
fieldOriginalyModified = revision.getLastModified();
}
}
public Reader getReader() throws OpenEditException
{
if ( exists() )
{
InputStreamReader in = null;
try
{
in = new InputStreamReader( getContentItem().getInputStream(), getCharacterEncoding() );
} catch ( Exception ex )
{
throw new OpenEditException(ex);
}
return in;
}
else
{
throw new ContentNotAvailableException("No such page " + getPath(),getPath() );
}
}
public Reader getReader(String inEncoding) throws OpenEditException
{
if ( exists() )
{
InputStreamReader in = null;
try
{
in = new InputStreamReader( getContentItem().getInputStream(), inEncoding );
} catch ( Exception ex )
{
throw new OpenEditException(ex);
}
return in;
}
else
{
throw new ContentNotAvailableException("No such page " + getPath(),getPath() );
}
}
protected long getOriginalyModified()
{
return fieldOriginalyModified;
}
/* (non-javadoc)
* @see org.jpublish.Page#getCharacterEncoding()
*/
public String getCharacterEncoding()
{
//Its UTF-8 unless otherwise setup in the xconf's
String encoding = getPageSettings().getPropertyValue("encoding",null);
if ( encoding == null)
{
return "UTF-8";
}
return encoding;
}
public String getContent() throws OpenEditException
{
StringWriter out = new StringWriter();
Reader reader = null;
try
{
reader = getReader();
new OutputFiller().fill( reader, out);
}
catch (IOException ex)
{
log.error( ex );
throw new OpenEditException(ex);
}
finally
{
FileUtils.safeClose(reader);
}
return out.toString();
}
/**
* @param inReq
*/
public WebPageRequest generate(WebPageRequest inReq, Output inOut) throws OpenEditException
{
WebPageRequest req = inReq;
if ( inReq.getPage() != this)
{
req = inReq.copy(this);
}
if ( !req.hasRedirected() )
{
for (Iterator iter = getGenerator().iterator(); iter.hasNext();)
{
Generator gen= (Generator) iter.next();
if ( gen.canGenerate(inReq))
{
gen.generate(req,this,inOut);
break;
}
}
}
return req;
}
/**
* This will contain innerlayout details
* @param inWebPageContext
* @param inOutputStream
*/
public void generate(WebPageRequest inWebPageContext, Writer inOutputStream)
{
WebPageRequest context = null;
if( inWebPageContext.getPage() == this )
{
context = inWebPageContext.copy(this);
}
else
{
context = inWebPageContext;
}
context.putPageValue("content", this);
PageStreamer streamer = inWebPageContext.getPageStreamer().copy();
Output out = new Output();
out.setWriter(inOutputStream);
streamer.setOutput(out);
context.putPageStreamer(streamer);
streamer.setWebPageRequest(context);
streamer.render();
}
public boolean isDynamic() {
return isHtml() || isJson();
}
/**
* @return
*/
public boolean isJson() {
String mime = getMimeType();
if ( mime != null && mime.endsWith("json"))
{
return true;
}
return false;
}
public boolean isHtml() {
String mime = getMimeType();
if ( mime != null && mime.endsWith("html"))
{
return true;
}
return false;
}
public boolean isImage() {
String mime = getMimeType();
if ( mime != null && mime.startsWith("image"))
{
return true;
}
return false;
}
public boolean isVideo() {
String mime = getMimeType();
if ( mime != null && mime.startsWith("video"))
{
return true;
}
return false;
}
public boolean isDraft()
{
if( getContentItem().getActualPath().indexOf(".draft.") > -1 && exists() )
{
return true;
}
return false;
}
public Permission getPermission(String inName)
{
return getPageSettings().getPermission(inName);
}
public List getPermissions()
{
return getPageSettings().getPermissions();
}
public List getParentPaths()
{
List parents = new ArrayList();
String path = getPath();
while( true )
{
if( path.length() == 0 || path.equals("/"))
{
break;
}
parents.add(0,path);
path = PathUtilities.extractDirectoryPath(path);
}
if( parents.size() > 0)
{
parents.add(0,"/");
}
else
{
parents.add("/");
}
Collections.sort(parents);
return parents;
}
public String getId()
{
String id = PathUtilities.makeId(getPath());
id = id.replace('/', '_');
return id;
}
public String getParentPath()
{
if( getPath().equals("/"))
{
return null;
}
String path = PathUtilities.extractDirectoryPath(getPath());
// urlpath is the address the link came in on
if( path.equals(""))
{
return "/";
}
return path;
}
public String getSourcePath() {
return getName();
}
public void setId(String inNewid) {
}
public void setName(String inName) {
// TODO Auto-generated method stub
}
public void setProperty(String inId, String inValue) {
getPageSettings().setProperty(inId, inValue);
}
public void setProperties(Map<String, String> inProperties)
{
getPageSettings().setProperties(inProperties);
}
public void setSourcePath(String inSourcepath) {
// TODO Auto-generated method stub
}
public long length()
{
return getContentItem().getLength();
}
public Map getProperties() {
return getPageSettings().getProperties();
}
public int compareTo(Object inO)
{
Page other = (Page)inO;
return getPath().compareTo(other.getPath());
}
public String getText(String inKey, String inLocale)
{
String text = getPageSettings().getTextLabels().getAutoText(this, inKey, inLocale);
return text;
}
public String replaceProperty(String inValue){
return getPageSettings().replaceProperty(inValue);
}
public void setValues(String inKey, Collection<String> inValues)
{
StringBuffer values = new StringBuffer();
for (Iterator iterator = inValues.iterator(); iterator.hasNext();)
{
String detail = (String) iterator.next();
values.append(detail);
if( iterator.hasNext())
{
values.append(" | ");
}
}
setProperty(inKey,values.toString());
}
}