/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Xml; | |
using System.Xml.Serialization; | |
using DotCMIS.CMISWebServicesReference; | |
namespace DotCMIS.Binding.AtomPub | |
{ | |
internal class AtomPubParser | |
{ | |
private static XmlSerializer RepositoryInfoSerializer; | |
private static XmlSerializer TypeDefintionSerializer; | |
private static XmlSerializer ObjectSerializer; | |
private static XmlSerializer AllowableActionsSerializer; | |
private static XmlSerializer AclSerializer; | |
static AtomPubParser() | |
{ | |
XmlRootAttribute repositoryInfoXmlRoot = new XmlRootAttribute("repositoryInfo"); | |
repositoryInfoXmlRoot.Namespace = AtomPubConstants.NamespaceRestAtom; | |
RepositoryInfoSerializer = new XmlSerializer(typeof(cmisRepositoryInfoType), repositoryInfoXmlRoot); | |
XmlRootAttribute typeDefinitionXmlRoot = new XmlRootAttribute("type"); | |
typeDefinitionXmlRoot.Namespace = AtomPubConstants.NamespaceRestAtom; | |
TypeDefintionSerializer = new XmlSerializer(typeof(cmisTypeDefinitionType), typeDefinitionXmlRoot); | |
XmlRootAttribute objectXmlRoot = new XmlRootAttribute("object"); | |
objectXmlRoot.Namespace = AtomPubConstants.NamespaceRestAtom; | |
ObjectSerializer = new XmlSerializer(typeof(cmisObjectType), objectXmlRoot); | |
XmlRootAttribute allowableActionsXmlRoot = new XmlRootAttribute("allowableActions"); | |
allowableActionsXmlRoot.Namespace = AtomPubConstants.NamespaceRestAtom; | |
AllowableActionsSerializer = new XmlSerializer(typeof(cmisAllowableActionsType), objectXmlRoot); | |
XmlRootAttribute aclXmlRoot = new XmlRootAttribute("accessControlList"); | |
aclXmlRoot.Namespace = AtomPubConstants.NamespaceRestAtom; | |
AclSerializer = new XmlSerializer(typeof(cmisAccessControlListType), objectXmlRoot); | |
} | |
private Stream stream; | |
private AtomBase parseResult; | |
public AtomPubParser(Stream stream) | |
{ | |
if (stream == null) | |
{ | |
throw new ArgumentNullException("stream"); | |
} | |
this.stream = stream; | |
} | |
public AtomBase GetParseResults() | |
{ | |
return parseResult; | |
} | |
public void Parse() | |
{ | |
XmlReaderSettings settings = new XmlReaderSettings(); | |
settings.IgnoreWhitespace = true; | |
settings.IgnoreComments = true; | |
XmlReader reader = XmlReader.Create(stream, settings); | |
try | |
{ | |
while (true) | |
{ | |
if (reader.IsStartElement()) | |
{ | |
if (AtomPubConstants.NamespaceAtom == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagFeed == reader.LocalName) | |
{ | |
parseResult = ParseFeed(reader); | |
break; | |
} | |
else if (AtomPubConstants.TagEntry == reader.LocalName) | |
{ | |
parseResult = ParseEntry(reader); | |
break; | |
} | |
} | |
else if (AtomPubConstants.NamespaceCMIS == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagAllowableActions == reader.LocalName) | |
{ | |
parseResult = ParseAllowableActions(reader); | |
break; | |
} | |
else if (AtomPubConstants.TagACL == reader.LocalName) | |
{ | |
parseResult = ParseACL(reader); | |
break; | |
} | |
} | |
else if (AtomPubConstants.NamespaceAPP == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagService == reader.LocalName) | |
{ | |
parseResult = ParseServiceDoc(reader); | |
break; | |
} | |
} | |
} | |
if (!reader.Read()) { break; } | |
} | |
} | |
finally | |
{ | |
try { reader.Close(); } | |
catch (Exception) { } | |
try { stream.Close(); } | |
catch (Exception) { } | |
} | |
} | |
private ServiceDoc ParseServiceDoc(XmlReader reader) | |
{ | |
ServiceDoc result = new ServiceDoc(); | |
reader.Read(); | |
while (true) | |
{ | |
if (reader.NodeType == XmlNodeType.Element) | |
{ | |
if (AtomPubConstants.NamespaceAPP == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagWorkspace == reader.LocalName) | |
{ | |
result.AddWorkspace(ParseWorkspace(reader)); | |
} | |
else | |
{ | |
skip(reader); | |
} | |
} | |
else | |
{ | |
skip(reader); | |
} | |
} | |
else if (reader.NodeType == XmlNodeType.EndElement) | |
{ | |
break; | |
} | |
else | |
{ | |
if (!reader.Read()) { break; } | |
} | |
} | |
return result; | |
} | |
private RepositoryWorkspace ParseWorkspace(XmlReader reader) | |
{ | |
RepositoryWorkspace workspace = new RepositoryWorkspace(); | |
reader.Read(); | |
while (true) | |
{ | |
if (reader.NodeType == XmlNodeType.Element) | |
{ | |
AtomElement element = ParseWorkspaceElement(reader); | |
if (element != null && element.Object is cmisRepositoryInfoType) | |
{ | |
workspace.Id = ((cmisRepositoryInfoType)element.Object).repositoryId; | |
} | |
workspace.AddElement(element); | |
} | |
else if (reader.NodeType == XmlNodeType.EndElement) | |
{ | |
break; | |
} | |
else | |
{ | |
if (!reader.Read()) { break; } | |
} | |
} | |
reader.Read(); | |
return workspace; | |
} | |
private AtomElement ParseWorkspaceElement(XmlReader reader) | |
{ | |
if (AtomPubConstants.NamespaceRestAtom == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagRepositoryInfo == reader.LocalName) | |
{ | |
return DeserializeRepositoryInfo(reader); | |
} | |
else if (AtomPubConstants.TagUriTemplate == reader.LocalName) | |
{ | |
return ParseTemplate(reader); | |
} | |
} | |
else if (AtomPubConstants.NamespaceAtom == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagLink == reader.LocalName) | |
{ | |
return ParseLink(reader); | |
} | |
} | |
else if (AtomPubConstants.NamespaceAPP == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagCollection == reader.LocalName) | |
{ | |
return ParseCollection(reader); | |
} | |
} | |
skip(reader); | |
return null; | |
} | |
private AtomElement ParseTemplate(XmlReader reader) | |
{ | |
Dictionary<string, string> result = new Dictionary<string, string>(); | |
string ns = reader.NamespaceURI; | |
string ln = reader.LocalName; | |
reader.Read(); | |
while (true) | |
{ | |
if (reader.NodeType == XmlNodeType.Element) | |
{ | |
if (AtomPubConstants.NamespaceRestAtom == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagTemplateTemplate == reader.LocalName) | |
{ | |
result["template"] = ReadText(reader); | |
} | |
else if (AtomPubConstants.TagTemplateType == reader.LocalName) | |
{ | |
result["type"] = ReadText(reader); | |
} | |
else | |
{ | |
skip(reader); | |
} | |
} | |
else | |
{ | |
skip(reader); | |
} | |
} | |
else if (reader.NodeType == XmlNodeType.EndElement) | |
{ | |
break; | |
} | |
else | |
{ | |
if (!reader.Read()) { break; } | |
} | |
} | |
reader.Read(); | |
return new AtomElement(ns, ln, result); | |
} | |
private AtomElement ParseCollection(XmlReader reader) | |
{ | |
Dictionary<string, string> result = new Dictionary<string, string>(); | |
string ns = reader.NamespaceURI; | |
string ln = reader.LocalName; | |
if (reader.MoveToAttribute("href")) | |
{ | |
result["href"] = reader.Value; | |
reader.MoveToElement(); | |
} | |
reader.Read(); | |
while (true) | |
{ | |
if (reader.NodeType == XmlNodeType.Element) | |
{ | |
if (AtomPubConstants.NamespaceRestAtom == reader.NamespaceURI && AtomPubConstants.TagCollectionType == reader.LocalName) | |
{ | |
result["collectionType"] = ReadText(reader); | |
} | |
else | |
{ | |
skip(reader); | |
} | |
} | |
else if (reader.NodeType == XmlNodeType.EndElement) | |
{ | |
break; | |
} | |
else | |
{ | |
if (!reader.Read()) { break; } | |
} | |
} | |
reader.Read(); | |
return new AtomElement(ns, ln, result); | |
} | |
private AtomElement ParseLink(XmlReader reader) | |
{ | |
AtomLink result = new AtomLink(); | |
string ns = reader.NamespaceURI; | |
string ln = reader.LocalName; | |
if (reader.HasAttributes) | |
{ | |
while (reader.MoveToNextAttribute()) | |
{ | |
if (AtomPubConstants.LinkRel == reader.Name) | |
{ | |
result.Rel = reader.Value; | |
} | |
else if (AtomPubConstants.LinkHref == reader.Name) | |
{ | |
result.Href = reader.Value; | |
} | |
else if (AtomPubConstants.LinkType == reader.Name) | |
{ | |
result.Type = reader.Value; | |
} | |
} | |
reader.MoveToElement(); | |
} | |
skip(reader); | |
return new AtomElement(ns, ln, result); | |
} | |
private AtomFeed ParseFeed(XmlReader reader) | |
{ | |
AtomFeed feed = new AtomFeed(); | |
reader.Read(); | |
while (true) | |
{ | |
if (reader.NodeType == XmlNodeType.Element) | |
{ | |
if (AtomPubConstants.NamespaceAtom == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagLink == reader.LocalName) | |
{ | |
feed.AddElement(ParseLink(reader)); | |
} | |
else if (AtomPubConstants.TagEntry == reader.LocalName) | |
{ | |
feed.AddEntry(ParseEntry(reader)); | |
} | |
else | |
{ | |
skip(reader); | |
} | |
} | |
else if (AtomPubConstants.NamespaceRestAtom == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagNumItems == reader.LocalName) | |
{ | |
feed.AddElement(ParseLong(reader)); | |
} | |
else | |
{ | |
skip(reader); | |
} | |
} | |
else | |
{ | |
skip(reader); | |
} | |
} | |
else if (reader.NodeType == XmlNodeType.EndElement) | |
{ | |
break; | |
} | |
else | |
{ | |
if (!reader.Read()) { break; } | |
} | |
} | |
reader.Read(); | |
return feed; | |
} | |
private AtomEntry ParseEntry(XmlReader reader) | |
{ | |
AtomEntry entry = new AtomEntry(); | |
reader.Read(); | |
while (true) | |
{ | |
if (reader.NodeType == XmlNodeType.Element) | |
{ | |
AtomElement element = ParseElement(reader); | |
if (element != null) | |
{ | |
entry.AddElement(element); | |
if (element.Object is cmisObjectType && ((cmisObjectType)element.Object).properties != null) | |
{ | |
foreach (cmisProperty prop in ((cmisObjectType)element.Object).properties.Items) | |
{ | |
if (PropertyIds.ObjectId == prop.propertyDefinitionId) | |
{ | |
entry.Id = ((cmisPropertyId)prop).value[0]; | |
} | |
} | |
} | |
else if (element.Object is cmisTypeDefinitionType) | |
{ | |
entry.Id = ((cmisTypeDefinitionType)element.Object).id; | |
} | |
} | |
} | |
else if (reader.NodeType == XmlNodeType.EndElement) | |
{ | |
break; | |
} | |
else | |
{ | |
if (!reader.Read()) { break; } | |
} | |
} | |
reader.Read(); | |
return entry; | |
} | |
private AtomAcl ParseACL(XmlReader reader) | |
{ | |
AtomAcl result = new AtomAcl(); | |
result.ACL = DeserializeACL(reader); | |
return result; | |
} | |
private AtomAllowableActions ParseAllowableActions(XmlReader reader) | |
{ | |
AtomAllowableActions result = new AtomAllowableActions(); | |
result.AllowableActions = DeserializeAllowableActions(reader); | |
return result; | |
} | |
private AtomElement ParseElement(XmlReader reader) | |
{ | |
if (AtomPubConstants.NamespaceRestAtom == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagObject == reader.LocalName) | |
{ | |
return DeserializeObject(reader); | |
} | |
else if (AtomPubConstants.TagPathSegment == reader.LocalName | |
|| AtomPubConstants.TagRelativePathSegment == reader.LocalName) | |
{ | |
return ParseText(reader); | |
} | |
else if (AtomPubConstants.TagType == reader.LocalName) | |
{ | |
return DeserializeTypeDefinition(reader); | |
} | |
else if (AtomPubConstants.TagChildren == reader.LocalName) | |
{ | |
return ParseChildren(reader); | |
} | |
} | |
else if (AtomPubConstants.NamespaceAtom == reader.NamespaceURI) | |
{ | |
if (AtomPubConstants.TagLink == reader.LocalName) | |
{ | |
return ParseLink(reader); | |
} | |
else if (AtomPubConstants.TagContent == reader.LocalName) | |
{ | |
return ParseAtomContentSrc(reader); | |
} | |
} | |
skip(reader); | |
return null; | |
} | |
private AtomElement ParseChildren(XmlReader reader) | |
{ | |
AtomElement result = null; | |
string childName = reader.LocalName; | |
string childNamespace = reader.NamespaceURI; | |
reader.Read(); | |
while (true) | |
{ | |
if (reader.NodeType == XmlNodeType.Element) | |
{ | |
if (AtomPubConstants.NamespaceAtom == reader.NamespaceURI && AtomPubConstants.TagFeed == reader.LocalName) | |
{ | |
result = new AtomElement(childNamespace, childName, ParseFeed(reader)); | |
} | |
else | |
{ | |
skip(reader); | |
} | |
} | |
else if (reader.NodeType == XmlNodeType.EndElement) | |
{ | |
break; | |
} | |
else | |
{ | |
if (!reader.Read()) { break; } | |
} | |
} | |
reader.Read(); | |
return result; | |
} | |
private AtomElement ParseAtomContentSrc(XmlReader reader) | |
{ | |
AtomLink result = new AtomLink(); | |
result.Rel = AtomPubConstants.LinkRelContent; | |
if (reader.MoveToAttribute(AtomPubConstants.ContentSrc)) | |
{ | |
result.Href = reader.Value; | |
reader.MoveToElement(); | |
} | |
skip(reader); | |
return new AtomElement(reader.NamespaceURI, reader.LocalName, result); | |
} | |
private AtomElement ParseText(XmlReader reader) | |
{ | |
string ns = reader.NamespaceURI; | |
string ln = reader.LocalName; | |
return new AtomElement(ns, ln, ReadText(reader)); | |
} | |
private AtomElement ParseLong(XmlReader reader) | |
{ | |
string ns = reader.NamespaceURI; | |
string ln = reader.LocalName; | |
return new AtomElement(ns, ln, Int64.Parse(ReadText(reader))); | |
} | |
private AtomElement DeserializeRepositoryInfo(XmlReader reader) | |
{ | |
string ns = reader.NamespaceURI; | |
string ln = reader.LocalName; | |
return new AtomElement(ns, ln, RepositoryInfoSerializer.Deserialize(reader)); | |
} | |
private AtomElement DeserializeTypeDefinition(XmlReader reader) | |
{ | |
string ns = reader.NamespaceURI; | |
string ln = reader.LocalName; | |
return new AtomElement(ns, ln, TypeDefintionSerializer.Deserialize(reader)); | |
} | |
private AtomElement DeserializeObject(XmlReader reader) | |
{ | |
string ns = reader.NamespaceURI; | |
string ln = reader.LocalName; | |
return new AtomElement(ns, ln, ObjectSerializer.Deserialize(reader)); | |
} | |
private cmisAccessControlListType DeserializeACL(XmlReader reader) | |
{ | |
return (cmisAccessControlListType)AclSerializer.Deserialize(reader); | |
} | |
private cmisAllowableActionsType DeserializeAllowableActions(XmlReader reader) | |
{ | |
return (cmisAllowableActionsType)AllowableActionsSerializer.Deserialize(reader); | |
} | |
private string ReadText(XmlReader reader) | |
{ | |
string text = null; | |
if (reader.Read()) | |
{ | |
text = reader.ReadContentAsString(); | |
reader.Read(); | |
} | |
return text; | |
} | |
private void skip(XmlReader reader) | |
{ | |
if (!reader.IsEmptyElement) | |
{ | |
int level = 1; | |
while (reader.Read()) | |
{ | |
if (reader.NodeType == XmlNodeType.Element) | |
{ | |
level++; | |
} | |
else if (reader.NodeType == XmlNodeType.EndElement) | |
{ | |
level--; | |
if (level == 0) | |
{ | |
break; | |
} | |
} | |
} | |
} | |
reader.Read(); | |
} | |
} | |
internal class AtomElement | |
{ | |
public string Namespace { get; private set; } | |
public string LocalName { get; private set; } | |
public object Object { get; private set; } | |
public AtomElement(string elementNamespace, string elementLocalName, object elementObject) | |
{ | |
Namespace = elementNamespace; | |
LocalName = elementLocalName; | |
Object = elementObject; | |
} | |
public override string ToString() | |
{ | |
return "{" + Namespace + "}" + LocalName + ": " + Object; | |
} | |
} | |
internal abstract class AtomBase | |
{ | |
public IList<AtomElement> elements = new List<AtomElement>(); | |
public abstract string GetAtomType(); | |
public IList<AtomElement> GetElements() | |
{ | |
return elements; | |
} | |
public void AddElement(AtomElement element) | |
{ | |
if (element != null) | |
{ | |
elements.Add(element); | |
} | |
} | |
} | |
internal class ServiceDoc : AtomBase | |
{ | |
private IList<RepositoryWorkspace> workspaces = new List<RepositoryWorkspace>(); | |
public override string GetAtomType() | |
{ | |
return "Service Document"; | |
} | |
public IList<RepositoryWorkspace> GetWorkspaces() | |
{ | |
return workspaces; | |
} | |
public void AddWorkspace(RepositoryWorkspace ws) | |
{ | |
if (ws != null) | |
{ | |
workspaces.Add(ws); | |
} | |
} | |
public override string ToString() | |
{ | |
return "Service Doc: " + workspaces; | |
} | |
} | |
internal class RepositoryWorkspace : AtomBase | |
{ | |
public string Id { get; set; } | |
public override string GetAtomType() | |
{ | |
return "Repository Workspace"; | |
} | |
public override string ToString() | |
{ | |
return "Workspace \"" + Id + "\": " + GetElements(); | |
} | |
} | |
internal class AtomEntry : AtomBase | |
{ | |
public string Id { get; set; } | |
public override string GetAtomType() | |
{ | |
return "Atom Entry"; | |
} | |
public override string ToString() | |
{ | |
return "Entry \"" + Id + "\": " + GetElements(); | |
} | |
} | |
internal class AtomFeed : AtomBase | |
{ | |
private IList<AtomEntry> entries = new List<AtomEntry>(); | |
public override string GetAtomType() | |
{ | |
return "Atom Feed"; | |
} | |
public IList<AtomEntry> GetEntries() | |
{ | |
return entries; | |
} | |
public void AddEntry(AtomEntry entry) | |
{ | |
if (entry != null) | |
{ | |
entries.Add(entry); | |
} | |
} | |
public override string ToString() | |
{ | |
return "Feed : " + GetElements() + " " + entries; | |
} | |
} | |
internal class AtomAcl : AtomBase | |
{ | |
public cmisAccessControlListType ACL { get; set; } | |
public override string GetAtomType() | |
{ | |
return "ACL"; | |
} | |
} | |
internal class AtomAllowableActions : AtomBase | |
{ | |
public cmisAllowableActionsType AllowableActions { get; set; } | |
public override string GetAtomType() | |
{ | |
return "Allowable Actions"; | |
} | |
} | |
internal class AtomLink | |
{ | |
public string Rel { get; set; } | |
public string Type { get; set; } | |
public string Href { get; set; } | |
public override string ToString() | |
{ | |
return "Link: rel=\"" + Rel + "\" type=\"" + Type + "\" href=\"" + Href + "\""; | |
} | |
} | |
} |