Package com.composum.sling.nodes.servlet
Class SourceModel
- java.lang.Object
-
- com.composum.sling.core.AbstractSlingBean
-
- com.composum.sling.nodes.console.ConsoleSlingBean
-
- com.composum.sling.nodes.servlet.SourceModel
-
- All Implemented Interfaces:
com.composum.sling.core.bean.RestrictedBean
,com.composum.sling.core.SlingBean
public class SourceModel extends ConsoleSlingBean
Model that can produce XML source, ZIP files or Vault-packages for it's resource. This is quite similar to what Jackrabbit Vault produces, but we make a few differences, since our main intention here is to produce good source code for our site. These are:
-
This is based on Sling
Resource
s and does not use JCR itself like Vault does. Thus, it could also be used for non-JCR based resources. (One exception is that we need JCR to determine whether a nodes children are orderable and to find out primaryType relationships, but we try to degrade gracefully if that fails.) -
We do not export properties that change on each im- and export, since importing and exporting a site
should not change it's source - compare
EXCLUDED_PROPS
. For instance, jcr:created* and jcr:lastModified* are omitted, as are the properties mix:versionable creates. Also, jcr:uuid is not exported, as it will change on each import and since we regard references to jcr:uuid as dangerous, to be used only sparingly if at all. (Composum uses absolute paths as references.) - In the .content.xml for a node with a jcr:content node, all subnodes of this node will be included, even if they happen to be a nt:folder. The only exception here are binary properties / files, which are written into separate files, since we don't want binary content in XML files.
- If nt:file have additional properties, we do always create an "extended file aggregate" with an additional directory {filename}.dir to avoid having parts of the file hidden in the .content.xml, invisible in a file browser
To summarize, we follow the following rules for our output.
- Resources with a primary type of nt:folder (or subtypes) or with a subnode named jcr:content are exported as a folder with a .content.xml. Other nodes (barring files and binary properties) are exported in the next higher .content.xml.
- Resources with type nt:file are exported as a file with a name according to their name; if they contain additional attributes an additional file {filename}_dir/.content.xml is created for them, which also contains other subnodes of the file node (barring files and binary attributes).
- Resources with type nt:resource that are not below a nt:file are exported into a file named like the resource with an extension added according to the mime type.
- Binary resources (except jcr:data below nt:file + nt:resource) are exported as a file {resource}/{
propertyname}.binary, with an entry
{propertyname}="{BINARY}"
in the .content.xml to declare the attribute with it's type. - If a node has orderable subnodes, it includes entries for all it's children - possibly empty nodes if they have their own folder / file according to the above rules.
- Only "source compatible" properties are exported - we ignore protected properties and properties that
change on import-export cycles. (See
EXCLUDED_PROPS
).
Limitations:
- Since we do not export jcr:uuid, references don't work.
- This will, obviously, not be quite identical to an export with Jackrabbit Vault, though it is compatible to be imported into JCR via Vault.
- See Also:
- "https://jackrabbit.apache.org/filevault/vaultfs.html"
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static class
SourceModel.DepthMode
static class
SourceModel.IOErrorOnCloseException
Is thrown when an exception appears duringZipOutputStream.close()
.static class
SourceModel.Property
protected static class
SourceModel.RenderingType
How the node is rendered in a zip.
-
Field Summary
Fields Modifier and Type Field Description static String
BASIC_INDENT
Indentation level for one level in the XML hierarchy in an XML document.protected NodesConfiguration
config
static String
DATE_FORMAT
Pattern forSimpleDateFormat
that creates a date suitable with XML sources.static com.composum.sling.core.filter.StringFilter
EXCLUDED_MIXINS
Matches mixins that do not belong into a source.static com.composum.sling.core.filter.StringFilter
EXCLUDED_PROPS
Matches a number of properties that do not belong into a source.protected Boolean[]
hasOrderableChildren
Whether the child nodes are known to be orderable - wrapped into array to distinguish "not known" from "not yet determined".protected Boolean[]
hasOrderableSiblings
Whether the siblings are known to be orderable - wrapped into array to distinguish "not known" from "not yet determined".protected static Pattern
PATH_WITHIN_JCR_CONTENT
protected Comparator<SourceModel.Property>
propertyComparator
protected List<SourceModel.Property>
propertyList
protected List<org.apache.sling.api.resource.Resource>
subnodeList
-
Constructor Summary
Constructors Constructor Description SourceModel(NodesConfiguration config, com.composum.sling.core.BeanContext context, org.apache.sling.api.resource.Resource resource)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description protected void
addNameNamespace(List<String> keys, String aName)
protected void
addNamespace(List<String> keys, String ns)
protected void
determineNamespaces(List<String> keys, boolean inFullCoverage)
String
escapeXmlName(String propertyName)
protected String
filesystemName(String aName)
Transforms the name into something usable for the filesystem.@NotNull String
getExportPath(@NotNull String path)
@NotNull String
getExportRootPath()
FileTime
getLastModified(org.apache.sling.api.resource.Resource rawResource)
String
getName()
protected String
getNamespace(String aName)
String
getPrimaryType()
protected Comparator<SourceModel.Property>
getPropertyComparator()
List<SourceModel.Property>
getPropertyList()
protected SourceModel.RenderingType
getRenderingType(org.apache.sling.api.resource.Resource aResource, boolean inFullCoverageNode)
This encodes what nodes are presented in which way nodes are represented in a Zip / Package.List<org.apache.sling.api.resource.Resource>
getSubnodeList()
protected String
getZipName(@NotNull String root)
Returns the name for the zip entry for this resource.protected String
getZipName(@NotNull String root, @NotNull String resourcePath)
Turns a resource path into a proper name for a zip file with the appropriate encoding of troublesome chars.boolean
hasOrderableChildren()
Returns true if the nodes children are ordered.protected Boolean
hasOrderableChildren(com.composum.sling.core.ResourceHandle aResource)
Returns true if the nodes children are ordered.boolean
hasOrderableSiblings()
Returns true if the nodes siblings are ordered.boolean
hasSubnodes()
protected boolean
isExcluded(SourceModel.Property property)
protected boolean
isFullCoverageNode()
boolean
isRootPath(@NotNull String aPath)
void
writeArchive(@NotNull OutputStream output)
Writes a "naked" Zip about the node: no package metadata, no parent nodes.protected void
writeBinaryProperties(@NotNull ZipOutputStream zipStream, @NotNull String root, @Nullable Queue<String> binaryProperties)
Writes the binary properties collected in {binaryProperties} into entries in the zip file.protected void
writeFile(@NotNull ZipOutputStream zipStream, @NotNull String root, @NotNull com.composum.sling.core.ResourceHandle file)
Writes the current node as a file node (not the jcr:content but the parent) incl.protected void
writeFilterXml(ZipOutputStream zipStream)
protected void
writeIntoZip(@NotNull ZipOutputStream zipStream, @NotNull String root, @NotNull SourceModel.DepthMode depthMode)
Writes a "naked" Zip about the node: no package metadata, no parent nodes.protected void
writeNamespaceAttributes(Writer writer, List<String> namespaces)
void
writePackage(OutputStream output, String group, String packageName, String version)
Writes a complete package about the node - arguments specify the package metadata.protected void
writePackageProperties(ZipOutputStream zipStream, String group, String aName, String version)
protected void
writeParents(@NotNull ZipOutputStream zipStream, @NotNull String root, @Nullable org.apache.sling.api.resource.Resource parent)
Writes all the .content.xml of the parents of root into the zip.protected void
writeProperties(@NotNull Writer writer, @NotNull String indent, @Nullable Queue<String> binaryProperties)
protected void
writeProperty(Writer writer, String indent, String propertyName, String escapedValue)
protected void
writeSubnodeOrder(Writer writer, String indent, boolean skipContentNode)
If the node has orderable children, we write a stub node to specify the node order.protected void
writeSubnodesAsXml(@NotNull Writer writer, @NotNull String indent, boolean inFullCoverageNode, @Nullable Queue<String> binaryProperties, @Nullable Queue<SourceModel> additionalFiles)
void
writeXmlFile(@NotNull Writer writer, boolean writeDeep)
Writes an XML file for the node, normally .content.xml, including an jcr:content node if present.protected void
writeXmlFile(@NotNull Writer writer, @NotNull SourceModel.DepthMode depthMode, @Nullable Queue<String> binaryProperties, @Nullable Queue<SourceModel> additionalFiles)
Writes an XML file for the node, normally .content.xml, including an jcr:content node if present.protected void
writeXmlSubnode(@NotNull Writer writer, @NotNull String indent, boolean inFullCoverageNode, @Nullable Queue<String> binaryProperties, @Nullable Queue<SourceModel> additionalFiles)
Writes the node including subnodes as XML, using the base indentation.-
Methods inherited from class com.composum.sling.nodes.console.ConsoleSlingBean
initialize
-
Methods inherited from class com.composum.sling.core.AbstractSlingBean
executeQuery, findBeans, findNodes, findNodes, findPathList, getContentResource, getDomId, getHasTitle, getId, getInherited, getInherited, getNode, getParent, getParent, getPath, getPermissible, getProperty, getProperty, getQueryManager, getRequest, getResolver, getResource, getResponse, getServiceKey, getSession, getSling, getStringId, getTitle, getType, getUrl, getUsername, initialize, isPermissible, isReadAllowed, isWriteAllowed, toString, toString
-
-
-
-
Field Detail
-
EXCLUDED_PROPS
public static final com.composum.sling.core.filter.StringFilter EXCLUDED_PROPS
Matches a number of properties that do not belong into a source.TODO move to configuration
-
EXCLUDED_MIXINS
public static final com.composum.sling.core.filter.StringFilter EXCLUDED_MIXINS
Matches mixins that do not belong into a source. E.g. rep:AccessControllable doesn't make sense since we do not export ACLs, anyway, and adding ACLs automatically adds this mixin.
-
DATE_FORMAT
public static final String DATE_FORMAT
Pattern forSimpleDateFormat
that creates a date suitable with XML sources.- See Also:
- Constant Field Values
-
BASIC_INDENT
public static final String BASIC_INDENT
Indentation level for one level in the XML hierarchy in an XML document.- See Also:
- Constant Field Values
-
PATH_WITHIN_JCR_CONTENT
protected static final Pattern PATH_WITHIN_JCR_CONTENT
-
config
protected final NodesConfiguration config
-
propertyList
protected transient List<SourceModel.Property> propertyList
-
subnodeList
protected transient List<org.apache.sling.api.resource.Resource> subnodeList
-
hasOrderableSiblings
protected transient Boolean[] hasOrderableSiblings
Whether the siblings are known to be orderable - wrapped into array to distinguish "not known" from "not yet determined".
-
hasOrderableChildren
protected transient Boolean[] hasOrderableChildren
Whether the child nodes are known to be orderable - wrapped into array to distinguish "not known" from "not yet determined".
-
propertyComparator
protected transient Comparator<SourceModel.Property> propertyComparator
-
-
Constructor Detail
-
SourceModel
public SourceModel(NodesConfiguration config, com.composum.sling.core.BeanContext context, org.apache.sling.api.resource.Resource resource)
-
-
Method Detail
-
getExportRootPath
@NotNull public @NotNull String getExportRootPath()
- Returns:
- the root path to use for exporting artifacts, honors a root path (mount poiunt) of an extended resolver
-
getExportPath
@NotNull public @NotNull String getExportPath(@NotNull @NotNull String path)
- Parameters:
path
- the path to map for exporting- Returns:
- the path relative to the export root path
-
isRootPath
public boolean isRootPath(@NotNull @NotNull String aPath)
- Parameters:
path
- a resource path in the resource repository tree; maybe a mounted resource path- Returns:
- 'true' if the path is equal to the export root path
-
getName
public String getName()
- Specified by:
getName
in interfacecom.composum.sling.core.SlingBean
- Overrides:
getName
in classcom.composum.sling.core.AbstractSlingBean
-
getPrimaryType
public String getPrimaryType()
-
getLastModified
public FileTime getLastModified(org.apache.sling.api.resource.Resource rawResource)
-
getPropertyList
public List<SourceModel.Property> getPropertyList()
-
isExcluded
protected boolean isExcluded(SourceModel.Property property)
-
hasSubnodes
public boolean hasSubnodes()
-
getSubnodeList
public List<org.apache.sling.api.resource.Resource> getSubnodeList()
-
writePackage
public void writePackage(OutputStream output, String group, String packageName, String version) throws IOException, SourceModel.IOErrorOnCloseException, javax.jcr.RepositoryException
Writes a complete package about the node - arguments specify the package metadata.- Throws:
IOException
- on IO errorsSourceModel.IOErrorOnCloseException
- is thrown when an IO error appears duringZipOutputStream.close()
, which writes the central directory of the zip which is not read by some consumers. We give them the possibility to distinguish these.javax.jcr.RepositoryException
-
hasOrderableSiblings
public boolean hasOrderableSiblings()
Returns true if the nodes siblings are ordered. Works only for JCR resources - if we cannot determine this, we return 'false'.
-
hasOrderableChildren
public boolean hasOrderableChildren()
Returns true if the nodes children are ordered. Works only for JCR resources - if we cannot determine this, we return null.
-
hasOrderableChildren
protected Boolean hasOrderableChildren(com.composum.sling.core.ResourceHandle aResource)
Returns true if the nodes children are ordered. Works only for JCR resources - if we cannot determine this, we return null.
-
writePackageProperties
protected void writePackageProperties(ZipOutputStream zipStream, String group, String aName, String version) throws IOException
- Throws:
IOException
-
writeFilterXml
protected void writeFilterXml(ZipOutputStream zipStream) throws IOException
- Throws:
IOException
-
writeParents
protected void writeParents(@NotNull @NotNull ZipOutputStream zipStream, @NotNull @NotNull String root, @Nullable @Nullable org.apache.sling.api.resource.Resource parent) throws IOException, javax.jcr.RepositoryException
Writes all the .content.xml of the parents of root into the zip.- Throws:
IOException
javax.jcr.RepositoryException
-
writeArchive
public void writeArchive(@NotNull @NotNull OutputStream output) throws IOException, javax.jcr.RepositoryException
Writes a "naked" Zip about the node: no package metadata, no parent nodes.- Throws:
IOException
javax.jcr.RepositoryException
-
writeIntoZip
protected void writeIntoZip(@NotNull @NotNull ZipOutputStream zipStream, @NotNull @NotNull String root, @NotNull @NotNull SourceModel.DepthMode depthMode) throws IOException, javax.jcr.RepositoryException
Writes a "naked" Zip about the node: no package metadata, no parent nodes. This might include entries about subnodes if {writeDeep}=true, and might include entries about binary properties.- Parameters:
zipStream
- the stream to write to, not closed.depthMode
- determines to what extent we write subnodes- Throws:
IOException
javax.jcr.RepositoryException
-
writeFile
protected void writeFile(@NotNull @NotNull ZipOutputStream zipStream, @NotNull @NotNull String root, @NotNull @NotNull com.composum.sling.core.ResourceHandle file) throws IOException, javax.jcr.RepositoryException
Writes the current node as a file node (not the jcr:content but the parent) incl. it's binary data and possibly additional data about nonstandard properties.- Throws:
IOException
javax.jcr.RepositoryException
-
writeBinaryProperties
protected void writeBinaryProperties(@NotNull @NotNull ZipOutputStream zipStream, @NotNull @NotNull String root, @Nullable @Nullable Queue<String> binaryProperties) throws IOException
Writes the binary properties collected in {binaryProperties} into entries in the zip file.- Throws:
IOException
-
getZipName
protected String getZipName(@NotNull @NotNull String root, @NotNull @NotNull String resourcePath)
Turns a resource path into a proper name for a zip file with the appropriate encoding of troublesome chars.
-
getZipName
protected String getZipName(@NotNull @NotNull String root)
Returns the name for the zip entry for this resource.
-
filesystemName
protected String filesystemName(String aName)
Transforms the name into something usable for the filesystem.
-
writeXmlFile
public void writeXmlFile(@NotNull @NotNull Writer writer, boolean writeDeep) throws IOException, javax.jcr.RepositoryException
Writes an XML file for the node, normally .content.xml, including an jcr:content node if present.- Parameters:
writeDeep
- also write subnodes; if false only properties of the node itself are written but no children (and no jcr:content).- Throws:
IOException
javax.jcr.RepositoryException
-
writeXmlFile
protected void writeXmlFile(@NotNull @NotNull Writer writer, @NotNull @NotNull SourceModel.DepthMode depthMode, @Nullable @Nullable Queue<String> binaryProperties, @Nullable @Nullable Queue<SourceModel> additionalFiles) throws IOException, javax.jcr.RepositoryException
Writes an XML file for the node, normally .content.xml, including an jcr:content node if present.- Parameters:
depthMode
- determines to what extent we write subnodesbinaryProperties
- if given, collects the full paths to binary properties (except jcr:data which is written as a binary fileadditionalFiles
- if given, collects theSourceModel
s that have to be written into another file- Throws:
IOException
javax.jcr.RepositoryException
-
writeSubnodesAsXml
protected void writeSubnodesAsXml(@NotNull @NotNull Writer writer, @NotNull @NotNull String indent, boolean inFullCoverageNode, @Nullable @Nullable Queue<String> binaryProperties, @Nullable @Nullable Queue<SourceModel> additionalFiles) throws IOException
- Throws:
IOException
-
writeXmlSubnode
protected void writeXmlSubnode(@NotNull @NotNull Writer writer, @NotNull @NotNull String indent, boolean inFullCoverageNode, @Nullable @Nullable Queue<String> binaryProperties, @Nullable @Nullable Queue<SourceModel> additionalFiles) throws IOException
Writes the node including subnodes as XML, using the base indentation.- Throws:
IOException
-
writeSubnodeOrder
protected void writeSubnodeOrder(Writer writer, String indent, boolean skipContentNode) throws IOException
If the node has orderable children, we write a stub node to specify the node order.- Throws:
IOException
-
writeProperties
protected void writeProperties(@NotNull @NotNull Writer writer, @NotNull @NotNull String indent, @Nullable @Nullable Queue<String> binaryProperties) throws IOException
- Throws:
IOException
-
writeProperty
protected void writeProperty(Writer writer, String indent, String propertyName, String escapedValue) throws IOException
- Throws:
IOException
-
writeNamespaceAttributes
protected void writeNamespaceAttributes(Writer writer, List<String> namespaces) throws javax.jcr.RepositoryException, IOException
- Throws:
javax.jcr.RepositoryException
IOException
-
getRenderingType
protected SourceModel.RenderingType getRenderingType(org.apache.sling.api.resource.Resource aResource, boolean inFullCoverageNode)
This encodes what nodes are presented in which way nodes are represented in a Zip / Package.- Parameters:
inFullCoverageNode
- if true we suppress folders - e.g. if we are within a jcr:content node or an RenderingType.XMLFILE node.
-
isFullCoverageNode
protected boolean isFullCoverageNode()
-
getPropertyComparator
protected Comparator<SourceModel.Property> getPropertyComparator()
-
-