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:
RestrictedBean,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
Resources 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 classSourceModel.DepthModestatic classSourceModel.IOErrorOnCloseExceptionIs thrown when an exception appears duringZipOutputStream.close().static classSourceModel.Propertyprotected static classSourceModel.RenderingTypeHow the node is rendered in a zip.-
Nested classes/interfaces inherited from class com.composum.sling.core.AbstractSlingBean
AbstractSlingBean.NodeClosure
-
-
Field Summary
Fields Modifier and Type Field Description static StringBASIC_INDENTIndentation level for one level in the XML hierarchy in an XML document.protected NodesConfigurationconfigstatic StringDATE_FORMATPattern forSimpleDateFormatthat creates a date suitable with XML sources.static StringFilterEXCLUDED_MIXINSMatches mixins that do not belong into a source.static StringFilterEXCLUDED_PROPSMatches a number of properties that do not belong into a source.protected Boolean[]hasOrderableChildrenWhether the child nodes are known to be orderable - wrapped into array to distinguish "not known" from "not yet determined".protected Boolean[]hasOrderableSiblingsWhether the siblings are known to be orderable - wrapped into array to distinguish "not known" from "not yet determined".protected List<String>nonExistingNamespacesSome things look like namespaces but aren't actual namespaces.protected static PatternPATH_WITHIN_JCR_CONTENTprotected Comparator<SourceModel.Property>propertyComparatorprotected List<SourceModel.Property>propertyListprotected List<org.apache.sling.api.resource.Resource>subnodeList-
Fields inherited from class com.composum.sling.core.AbstractSlingBean
context, queryManager, request, resolver, resource, response, session, sling
-
-
Constructor Summary
Constructors Constructor Description SourceModel(NodesConfiguration config, BeanContext context, org.apache.sling.api.resource.Resource resource)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description protected voidaddNameNamespace(List<String> keys, String aName)protected voidaddNamespace(List<String> keys, String ns)protected voiddetermineNamespaces(List<String> keys, boolean inFullCoverage)StringescapeXmlName(String propertyName)protected StringfilesystemName(String aName)Transforms the name into something usable for the filesystem.@NotNull StringgetExportPath(@NotNull String path)@NotNull StringgetExportRootPath()FileTimegetLastModified(org.apache.sling.api.resource.Resource rawResource)StringgetName()returns the name of the resource wrapped by this beanprotected StringgetNamespace(String aName)StringgetPrimaryType()protected Comparator<SourceModel.Property>getPropertyComparator()List<SourceModel.Property>getPropertyList()protected SourceModel.RenderingTypegetRenderingType(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 StringgetZipName(@NotNull String root)Returns the name for the zip entry for this resource.protected StringgetZipName(@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.booleanhasOrderableChildren()Returns true if the nodes children are ordered.protected BooleanhasOrderableChildren(ResourceHandle aResource)Returns true if the nodes children are ordered.booleanhasOrderableSiblings()Returns true if the nodes siblings are ordered.booleanhasSubnodes()protected booleanisExcluded(SourceModel.Property property)protected booleanisFullCoverageNode()booleanisRootPath(@NotNull String aPath)voidwriteArchive(@NotNull OutputStream output)Writes a "naked" Zip about the node: no package metadata, no parent nodes.protected voidwriteBinaryProperties(@NotNull ZipOutputStream zipStream, @NotNull String root, @Nullable Queue<String> binaryProperties)Writes the binary properties collected in {binaryProperties} into entries in the zip file.protected voidwriteFile(@NotNull ZipOutputStream zipStream, @NotNull String root, @NotNull ResourceHandle file)Writes the current node as a file node (not the jcr:content but the parent) incl.protected voidwriteFilterXml(ZipOutputStream zipStream)protected voidwriteIntoZip(@NotNull ZipOutputStream zipStream, @NotNull String root, @NotNull SourceModel.DepthMode depthMode)Writes a "naked" Zip about the node: no package metadata, no parent nodes.protected voidwriteNamespaceAttributes(Writer writer, List<String> namespaces)voidwritePackage(OutputStream output, String group, String packageName, String version)Writes a complete package about the node - arguments specify the package metadata.protected voidwritePackageProperties(ZipOutputStream zipStream, String group, String aName, String version)protected voidwriteParents(@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 voidwriteProperties(@NotNull Writer writer, @NotNull String indent, @Nullable Queue<String> binaryProperties)protected voidwriteProperty(Writer writer, String indent, String propertyName, String escapedValue)protected voidwriteSubnodeOrder(Writer writer, String indent, boolean skipContentNode)If the node has orderable children, we write a stub node to specify the node order.protected voidwriteSubnodesAsXml(@NotNull Writer writer, @NotNull String indent, boolean inFullCoverageNode, @Nullable Queue<String> binaryProperties, @Nullable Queue<SourceModel> additionalFiles)voidwriteXmlFile(@NotNull Writer writer, boolean writeDeep)Writes an XML file for the node, normally .content.xml, including an jcr:content node if present.protected voidwriteXmlFile(@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 voidwriteXmlSubnode(@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 StringFilter EXCLUDED_PROPS
Matches a number of properties that do not belong into a source.TODO move to configuration
-
EXCLUDED_MIXINS
public static final 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 forSimpleDateFormatthat 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, 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:
aPath- 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()
Description copied from interface:SlingBeanreturns the name of the resource wrapped by this bean- Specified by:
getNamein interfaceSlingBean- Overrides:
getNamein classAbstractSlingBean
-
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(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.RepositoryExceptionWrites all the .content.xml of the parents of root into the zip.- Throws:
IOExceptionjavax.jcr.RepositoryException
-
writeArchive
public void writeArchive(@NotNull @NotNull OutputStream output) throws IOException, javax.jcr.RepositoryExceptionWrites a "naked" Zip about the node: no package metadata, no parent nodes.- Throws:
IOExceptionjavax.jcr.RepositoryException
-
writeIntoZip
protected void writeIntoZip(@NotNull @NotNull ZipOutputStream zipStream, @NotNull @NotNull String root, @NotNull @NotNull SourceModel.DepthMode depthMode) throws IOException, javax.jcr.RepositoryExceptionWrites 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:
IOExceptionjavax.jcr.RepositoryException
-
writeFile
protected void writeFile(@NotNull @NotNull ZipOutputStream zipStream, @NotNull @NotNull String root, @NotNull @NotNull ResourceHandle file) throws IOException, javax.jcr.RepositoryExceptionWrites 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:
IOExceptionjavax.jcr.RepositoryException
-
writeBinaryProperties
protected void writeBinaryProperties(@NotNull @NotNull ZipOutputStream zipStream, @NotNull @NotNull String root, @Nullable @Nullable Queue<String> binaryProperties) throws IOExceptionWrites 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.RepositoryExceptionWrites 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:
IOExceptionjavax.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.RepositoryExceptionWrites 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 theSourceModels that have to be written into another file- Throws:
IOExceptionjavax.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 IOExceptionWrites 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.RepositoryExceptionIOException
-
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()
-
-