- Incorporate JCR project into Repository project

- Single configuration entry point for JCR and non-JCR clients (i.e. application-context.xml)
- Addition of build-war, incremental-war build targets (no deploy)
- Remove build of JCR TCK war file by default

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2777 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
David Caruana
2006-05-05 16:33:22 +00:00
parent c29f0fd4f1
commit 19e3138e1c
80 changed files with 14665 additions and 3 deletions

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import java.util.List;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import org.alfresco.jcr.session.SessionImpl;
import org.alfresco.jcr.util.AbstractRangeIterator;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
/**
* Alfresco implementation of a Node Iterator
*
* @author David Caruana
*/
public class ChildAssocNodeIteratorImpl extends AbstractRangeIterator
implements NodeIterator
{
private SessionImpl sessionImpl;
private List<ChildAssociationRef> childAssocs;
/**
* Construct
*
* @param context session context
* @param nodes node list
*/
public ChildAssocNodeIteratorImpl(SessionImpl sessionImpl, List<ChildAssociationRef> childAssocs)
{
this.sessionImpl = sessionImpl;
this.childAssocs = childAssocs;
}
/* (non-Javadoc)
* @see javax.jcr.NodeIterator#nextNode()
*/
public Node nextNode()
{
long position = skip();
ChildAssociationRef childAssocRef = childAssocs.get((int)position);
NodeImpl nodeImpl = new NodeImpl(sessionImpl, childAssocRef.getChildRef());
return nodeImpl.getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.RangeIterator#getSize()
*/
public long getSize()
{
return childAssocs.size();
}
/* (non-Javadoc)
* @see java.util.Iterator#next()
*/
public Object next()
{
return nextNode();
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import javax.jcr.AccessDeniedException;
import javax.jcr.InvalidItemStateException;
import javax.jcr.Item;
import javax.jcr.ItemExistsException;
import javax.jcr.ReferentialIntegrityException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.version.VersionException;
import org.alfresco.jcr.session.SessionImpl;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
/**
* Alfresco Implementation of an Item
*
* @author David Caruana
*/
public abstract class ItemImpl implements Item
{
protected SessionImpl session;
/**
* Construct
*
* @param session
*/
public ItemImpl(SessionImpl session)
{
this.session = session;
}
/**
* Get the Session implementation
*
* @return session implementation
*/
public SessionImpl getSessionImpl()
{
return session;
}
/**
* Get the Item Proxy
*
* @return the proxy
*/
public abstract Item getProxy();
/* (non-Javadoc)
* @see javax.jcr.Item#getSession()
*/
public Session getSession() throws RepositoryException
{
return session.getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Item#isNew()
*/
public boolean isNew()
{
return false;
}
/* (non-Javadoc)
* @see javax.jcr.Item#isModified()
*/
public boolean isModified()
{
return false;
}
/* (non-Javadoc)
* @see javax.jcr.Item#save()
*/
public void save() throws AccessDeniedException, ItemExistsException, ConstraintViolationException, InvalidItemStateException, ReferentialIntegrityException, VersionException, LockException, NoSuchNodeTypeException, RepositoryException
{
AlfrescoTransactionSupport.flush();
}
/* (non-Javadoc)
* @see javax.jcr.Item#refresh(boolean)
*/
public void refresh(boolean keepChanges) throws InvalidItemStateException, RepositoryException
{
throw new UnsupportedRepositoryOperationException();
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import java.util.List;
import javax.jcr.PathNotFoundException;
import org.alfresco.jcr.session.SessionImpl;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.search.SearchService;
/**
* Responsible for finding JCR Items (Nodes, Properties) from Alfresco equivalents
*
* @author David Caruana
*
*/
public class ItemResolver
{
/**
* Create an Item from a JCR Path
*
* @param context session context
* @param from starting node for path
* @param path the path
* @return the Item (Node or Property)
* @throws PathNotFoundException
*/
public static ItemImpl findItem(SessionImpl context, NodeRef from, String path)
throws PathNotFoundException
{
ItemImpl item = null;
NodeRef nodeRef = getNodeRef(context, from, path);
if (nodeRef != null)
{
item = new NodeImpl(context, nodeRef);
}
else
{
// TODO: create property
}
if (item == null)
{
throw new PathNotFoundException("Path " + path + " not found.");
}
return item;
}
/**
* Create an Node from a JCR Path
*
* @param context session context
* @param from starting node for path
* @param path the path
* @return the Item (Node or Property)
* @throws PathNotFoundException
*/
public static NodeImpl findNode(SessionImpl context, NodeRef from, String path)
throws PathNotFoundException
{
NodeRef nodeRef = getNodeRef(context, from, path);
if (nodeRef == null)
{
throw new PathNotFoundException("A node does not exist at path " + path + " relative to node " + from);
}
return new NodeImpl(context, nodeRef);
}
/**
* Determine if Item exists
*
* @param context session context
* @param from starting node for path
* @param path the path
* @return true => exists, false => no it doesn't
*/
public static boolean itemExists(SessionImpl context, NodeRef from, String path)
{
boolean exists = nodeExists(context, from, path);
if (!exists)
{
// TODO: Check for property
}
return exists;
}
/**
* Determine if Node exists
*
* @param context session context
* @param from starting node for path
* @param path the path
* @return true => exists, false => no it doesn't
*/
public static boolean nodeExists(SessionImpl context, NodeRef from, String path)
{
NodeRef nodeRef = getNodeRef(context, from, path);
return nodeRef != null;
}
/**
* Gets the Node Reference for the node at the specified path
*
* @param context session context
* @param from the starting node for the path
* @param path the path
* @return the node reference (or null if not found)
*/
public static NodeRef getNodeRef(SessionImpl context, NodeRef from, String path)
{
NodeRef nodeRef = null;
// TODO: Support JCR Path
// TODO: Catch malformed path and return false (per Specification)
SearchService search = context.getRepositoryImpl().getServiceRegistry().getSearchService();
List<NodeRef> nodeRefs = search.selectNodes(from, path, null, context.getNamespaceResolver(), false);
if (nodeRefs != null && nodeRefs.size() > 0)
{
nodeRef = nodeRefs.get(0);
}
return nodeRef;
}
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import java.util.StringTokenizer;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.QName;
/**
* JCR Path Helper
*
* @author David Caruana
*/
public class JCRPath
{
private Path path;
/**
* Constuct path from string representation of path
*
* @param strPath
*/
public JCRPath(NamespacePrefixResolver resolver, String strPath)
{
// TODO: replace this simple parse for full path syntax
boolean root = false;
int pos = 0;
path = new Path();
StringTokenizer tokenizer = new StringTokenizer(strPath, "/", true);
while (tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if (pos == 0 && token.equals("/"))
{
root = true;
}
else if (!token.equals("/"))
{
if (root)
{
path.append(new RootSimpleElement(resolver, token));
root = false;
}
else
{
path.append(new SimpleElement(resolver, token));
}
}
pos++;
}
}
/**
* Get the Path
*
* @return the underling path
*/
public Path getPath()
{
return path;
}
@Override
public String toString()
{
return path.toString();
}
/**
* Simple Path Element used for building JCR Paths
*
* @author David Caruana
*/
public static class SimpleElement extends Path.Element
{
private static final long serialVersionUID = -6510331182652872996L;
private QName path;
/**
* @param resolver namespace prefix resolver
* @param path path element name
*/
public SimpleElement(QName path)
{
this.path = path;
}
/**
* @param path path element name
*/
public SimpleElement(NamespacePrefixResolver resolver, String path)
{
this.path = QName.createQName(path, resolver);
}
/**
* Get the QName representation of Path
*/
public QName getQName()
{
return path;
}
@Override
public String getElementString()
{
return path.toString();
}
@Override
public String getPrefixedString(NamespacePrefixResolver resolver)
{
return path.toPrefixString(resolver);
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object o)
{
if(o == this)
{
return true;
}
if(!(o instanceof SimpleElement))
{
return false;
}
SimpleElement other = (SimpleElement)o;
return this.path.equals(other.path);
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode()
{
return path.hashCode();
}
}
/**
* Root Path Element
*
* @author David Caruana
*/
public static class RootSimpleElement extends SimpleElement
{
private static final long serialVersionUID = -4827016063963328324L;
/**
* Construct
*
* @param path
*/
public RootSimpleElement(NamespacePrefixResolver resolver, String path)
{
super(resolver, path);
}
@Override
public String getElementString()
{
return "/" + super.getElementString();
}
@Override
public String getPrefixedString(NamespacePrefixResolver resolver)
{
return "/" + super.getPrefixedString(resolver);
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNamePattern;
/**
* Checks if the QName matches the passed JCR pattern.
*
* The pattern may be a full name or a partial name with one or more wildcard
* characters ("*"), or a disjunction (using the "|" character to represent
* logical OR) of these. For example,
*
* isMatch("jcr:* | myapp:report | my doc")
*
* Note that leading and trailing whitespace around a disjunct is ignored,
* but whitespace within a disjunct forms part of the pattern to be matched.
*
* The EBNF for namePattern is:
*
* namePattern ::= disjunct {'|' disjunct}
* disjunct ::= name [':' name]
* name ::= '*' | ['*'] fragment {'*' fragment} ['*']
* fragment ::= char {char}
* char ::= nonspace | ' '
* nonspace ::= (* Any Unicode character except: '/', ':', '[', ']', '*', ''', '"', '|' or any whitespace character *)
*/
public class JCRPatternMatch implements QNamePattern
{
private List<String> searches = new ArrayList<String>();
private NamespacePrefixResolver resolver;
/**
* Construct
* @param pattern JCR Pattern
* @param resolver Namespace Prefix Resolver
*/
public JCRPatternMatch(String pattern, NamespacePrefixResolver resolver)
{
// TODO: Check for valid pattern
// Convert to regular expression
String regexPattern = pattern.replaceAll("\\*", ".*");
// Split into independent search strings
StringTokenizer tokenizer = new StringTokenizer(regexPattern, "|", false);
while (tokenizer.hasMoreTokens())
{
String disjunct = tokenizer.nextToken().trim();
this.searches.add(disjunct);
}
this.resolver = resolver;
}
/* (non-Javadoc)
* @see org.alfresco.service.namespace.QNamePattern#isMatch(org.alfresco.service.namespace.QName)
*/
public boolean isMatch(QName qname)
{
String prefixedName = qname.toPrefixString(resolver);
for (String search : searches)
{
if (prefixedName.matches(search))
{
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,416 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import javax.jcr.RepositoryException;
import javax.jcr.ValueFormatException;
import org.alfresco.jcr.session.SessionImpl;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.repository.datatype.TypeConversionException;
import org.alfresco.service.cmr.repository.datatype.TypeConverter;
import org.alfresco.service.namespace.NamespaceException;
import org.alfresco.service.namespace.QName;
/**
* Responsible for converting Alfresco values to JCR values.
*
* @author David Caruana
*
*/
public class JCRTypeConverter
{
private SessionTypeConverter jcrTypeConverter;
/**
* Construct
*
* @param session
*/
public JCRTypeConverter(SessionImpl session)
{
this.jcrTypeConverter = new SessionTypeConverter(session);
}
/**
* Get the underlying Converter
*
* @return type converter
*/
public TypeConverter getConverter()
{
return jcrTypeConverter;
}
/**
* Convert to JCR Reference Value
*
* @param session
* @param value
* @return
* @throws ValueFormatException
* @throws RepositoryException
*/
public NodeImpl referenceValue(Object value) throws ValueFormatException, RepositoryException
{
NodeRef nodeRef = (NodeRef)convert(NodeRef.class, value);
return new NodeImpl(jcrTypeConverter.getSession(), nodeRef);
}
/**
* Convert to JCR String Value
*
* @param value
* @return
* @throws ValueFormatException
* @throws RepositoryException
*/
public String stringValue(Object value) throws ValueFormatException, RepositoryException
{
return (String)convert(String.class, value);
}
/**
* Convert to JCR Stream Value
*
* @param value
* @return
* @throws IllegalStateException
* @throws RepositoryException
*/
public InputStream streamValue(Object value) throws IllegalStateException, RepositoryException
{
return (InputStream)convert(InputStream.class, value);
}
/**
* Convert to JCR Long Value
*
* @param value
* @return
* @throws ValueFormatException
* @throws IllegalStateException
* @throws RepositoryException
*/
public long longValue(Object value) throws ValueFormatException, IllegalStateException, RepositoryException
{
try
{
return jcrTypeConverter.longValue(value);
}
catch(Exception e)
{
translateException(e);
throw new RepositoryException(e);
}
}
/**
* Convert to JCR Double Value
*
* @param value
* @return
* @throws ValueFormatException
* @throws IllegalStateException
* @throws RepositoryException
*/
public double doubleValue(Object value) throws ValueFormatException, IllegalStateException, RepositoryException
{
try
{
return jcrTypeConverter.doubleValue(value);
}
catch(Exception e)
{
translateException(e);
throw new RepositoryException(e);
}
}
/**
* Convert to JCR Date Value
*
* @param value
* @return
* @throws ValueFormatException
* @throws IllegalStateException
* @throws RepositoryException
*/
public Calendar dateValue(Object value) throws ValueFormatException, IllegalStateException, RepositoryException
{
Date date = (Date)convert(Date.class, value);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar;
}
/**
* Convert to JCR Boolean Value
*
* @param value
* @return
* @throws ValueFormatException
* @throws IllegalStateException
* @throws RepositoryException
*/
public boolean booleanValue(Object value) throws ValueFormatException, IllegalStateException, RepositoryException
{
try
{
return jcrTypeConverter.booleanValue(value);
}
catch(Exception e)
{
translateException(e);
throw new RepositoryException(e);
}
}
/**
* Convert to JCR Name Value
*
* @param value
* @return
* @throws ValueFormatException
* @throws IllegalStateException
* @throws RepositoryException
*/
public QName nameValue(Object value) throws ValueFormatException, IllegalStateException, RepositoryException
{
return convert(QName.class, value);
}
/**
* Convert to JCR Path Value
*
* @param value
* @return
* @throws ValueFormatException
* @throws IllegalStateException
* @throws RepositoryException
*/
public Path pathValue(Object value) throws ValueFormatException, IllegalStateException, RepositoryException
{
return convert(Path.class, value);
}
/**
* General conversion method using JCR converters
*
* @param propertyType datatype to convert to
* @param value the value to convert
* @return the converted value
* @throws RepositoryException
*/
public final Object convert(DataTypeDefinition propertyType, Object value)
throws RepositoryException
{
try
{
return jcrTypeConverter.convert(propertyType, value);
}
catch(Exception e)
{
translateException(e);
throw new RepositoryException(e);
}
}
/**
* General conversion method using JCR converters
*
* @param <T> class
* @param c class
* @param value value to convert
* @return converted value
* @throws RepositoryException
*/
public final <T> T convert(Class<T> c, Object value)
throws RepositoryException
{
try
{
return jcrTypeConverter.convert(c, value);
}
catch(Exception e)
{
translateException(e);
throw new RepositoryException(e);
}
}
/**
* Catch and translate value conversion errors
*
* @param e exception to translate
* @throws ValueFormatException value formatting exception
*/
private static void translateException(Exception e) throws ValueFormatException
{
if (e instanceof TypeConversionException ||
e instanceof NumberFormatException)
{
throw new ValueFormatException(e);
}
}
/**
* Data Type Converter that takes into account JCR session context
*
* @author David Caruana
*/
private static class SessionTypeConverter extends TypeConverter
{
private SessionImpl session;
/**
* Construct
*
* @param session session context
*/
public SessionTypeConverter(SessionImpl session)
{
this.session = session;
/**
* Converter to translating string to QName as prefix:localName
*/
addConverter(String.class, QName.class, new TypeConverter.Converter<String, QName>()
{
public QName convert(String source)
{
try
{
return QName.createQName(source, SessionTypeConverter.this.session.getNamespaceResolver());
}
catch(NamespaceException e)
{
throw new TypeConversionException("Cannot convert " + source + " to qualified name", e);
}
}
});
/**
* Converter to translating string to QName as prefix:localName
*/
addConverter(String.class, Path.class, new TypeConverter.Converter<String, Path>()
{
public Path convert(String source)
{
try
{
return new JCRPath(SessionTypeConverter.this.session.getNamespaceResolver(), source).getPath();
}
catch(NamespaceException e)
{
throw new TypeConversionException("Cannot convert " + source + " to qualified name", e);
}
}
});
/**
* Converter for translating QName to string as prefix:localName
*/
addConverter(QName.class, String.class, new TypeConverter.Converter<QName, String>()
{
public String convert(QName source)
{
try
{
return source.toPrefixString(SessionTypeConverter.this.session.getNamespaceResolver());
}
catch(NamespaceException e)
{
throw new TypeConversionException("Cannot convert " + source + " to qualified name", e);
}
}
});
/**
* Converter for translating Path to string as prefix:localName
*/
addConverter(Path.class, String.class, new TypeConverter.Converter<Path, String>()
{
public String convert(Path source)
{
try
{
return source.toPrefixString(SessionTypeConverter.this.session.getNamespaceResolver());
}
catch(NamespaceException e)
{
throw new TypeConversionException("Cannot convert " + source + " to qualified name", e);
}
}
});
/**
* Converter for translating Node Ref to JCR Id
*/
addConverter(NodeRef.class, String.class, new TypeConverter.Converter<NodeRef, String>()
{
public String convert(NodeRef source)
{
return source.getId();
}
});
}
/**
* Get the session
*
* @return session
*/
public SessionImpl getSession()
{
return session;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.datatype.TypeConverter#getConverter(java.lang.Class, java.lang.Class)
*/
@Override
@SuppressWarnings("unchecked")
public <F, T> Converter getConverter(Class<F> source, Class<T> dest)
{
Converter converter = super.getConverter(source, dest);
if (converter == null)
{
converter = DefaultTypeConverter.INSTANCE.getConverter(source, dest);
if (converter instanceof DynamicTwoStageConverter)
{
DynamicTwoStageConverter dynamic = (DynamicTwoStageConverter)converter;
converter = addDynamicTwoStageConverter(dynamic.getFrom(), dynamic.getIntermediate(), dynamic.getTo());
}
}
return converter;
}
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.lock.Lock;
import javax.jcr.lock.LockException;
import org.alfresco.jcr.util.JCRProxyFactory;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.repository.NodeService;
/**
* Alfresco implementation of a JCR Lock
*
* @author David Caruana
*/
public class LockImpl implements Lock
{
private NodeImpl node;
private Lock proxy = null;
/**
* Constructor
*
* @param node node holding lock
*/
public LockImpl(NodeImpl node)
{
this.node = node;
}
/**
* Create proxied JCR Lock
*
* @return lock
*/
public Lock getProxy()
{
if (proxy == null)
{
proxy = (Lock)JCRProxyFactory.create(this, Lock.class, node.session);
}
return proxy;
}
/*
* (non-Javadoc)
* @see javax.jcr.lock.Lock#getLockOwner()
*/
public String getLockOwner()
{
String lockOwner = null;
NodeService nodeService = node.session.getRepositoryImpl().getServiceRegistry().getNodeService();
if (nodeService.hasAspect(node.getNodeRef(), ContentModel.ASPECT_LOCKABLE))
{
lockOwner = (String)nodeService.getProperty(node.getNodeRef(), ContentModel.PROP_LOCK_OWNER);
}
return lockOwner;
}
/*
* (non-Javadoc)
* @see javax.jcr.lock.Lock#isDeep()
*/
public boolean isDeep()
{
return false;
}
/*
* (non-Javadoc)
* @see javax.jcr.lock.Lock#getNode()
*/
public Node getNode()
{
return node.getProxy();
}
/*
* (non-Javadoc)
* @see javax.jcr.lock.Lock#getLockToken()
*/
public String getLockToken()
{
LockService lockService = node.session.getRepositoryImpl().getServiceRegistry().getLockService();
LockStatus lockStatus = lockService.getLockStatus(node.getNodeRef());
return lockStatus.equals(LockStatus.LOCK_OWNER) ? node.getNodeRef().toString() : null;
}
/*
* (non-Javadoc)
* @see javax.jcr.lock.Lock#isLive()
*/
public boolean isLive() throws RepositoryException
{
return getLockToken() == null ? false : true;
}
/*
* (non-Javadoc)
* @see javax.jcr.lock.Lock#isSessionScoped()
*/
public boolean isSessionScoped()
{
return false;
}
/*
* (non-Javadoc)
* @see javax.jcr.lock.Lock#refresh()
*/
public void refresh() throws LockException, RepositoryException
{
// note: for now, this is a noop
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import java.util.List;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.query.QueryResult;
import org.alfresco.jcr.session.SessionImpl;
import org.alfresco.jcr.util.AbstractRangeIterator;
import org.alfresco.jcr.util.JCRProxyFactory;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Alfresco implementation of a Node Iterator
*
* @author David Caruana
*/
public class NodeRefNodeIteratorImpl extends AbstractRangeIterator
implements NodeIterator
{
private SessionImpl sessionImpl;
private List<NodeRef> nodeRefs;
/**
* Construct
*
* @param context session context
* @param nodes node list
*/
public NodeRefNodeIteratorImpl(SessionImpl sessionImpl, List<NodeRef> nodeRefs)
{
this.sessionImpl = sessionImpl;
this.nodeRefs = nodeRefs;
}
/* (non-Javadoc)
* @see javax.jcr.NodeIterator#nextNode()
*/
public Node nextNode()
{
long position = skip();
NodeRef nodeRef = nodeRefs.get((int)position);
NodeImpl nodeImpl = new NodeImpl(sessionImpl, nodeRef);
return nodeImpl.getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.RangeIterator#getSize()
*/
public long getSize()
{
return nodeRefs.size();
}
/* (non-Javadoc)
* @see java.util.Iterator#next()
*/
public Object next()
{
return nextNode();
}
}

View File

@@ -0,0 +1,684 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import javax.jcr.AccessDeniedException;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.ItemVisitor;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.version.VersionException;
import org.alfresco.jcr.api.JCRNodeRef;
import org.alfresco.jcr.dictionary.DataTypeMap;
import org.alfresco.jcr.dictionary.PropertyDefinitionImpl;
import org.alfresco.jcr.util.JCRProxyFactory;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.repository.datatype.TypeConversionException;
import org.alfresco.service.namespace.QName;
/**
* Alfresco implementation of a Property
*
* @author David Caruana
*/
public class PropertyImpl extends ItemImpl implements Property
{
private NodeImpl node;
private QName name;
private Property proxy = null;
/**
* Constructor
*
* @param session
*/
public PropertyImpl(NodeImpl node, QName name)
{
super(node.session);
this.node = node;
this.name = name;
}
/**
* Create proxied JCR Property
*
* @return property
*/
@Override
public Property getProxy()
{
if (proxy == null)
{
proxy = (Property)JCRProxyFactory.create(this, Property.class, session);
}
return proxy;
}
/* (non-Javadoc)
* @see javax.jcr.Item#remove()
*/
public void remove() throws VersionException, LockException, ConstraintViolationException, RepositoryException
{
setValue((Value)null);
}
/* (non-Javadoc)
* @see javax.jcr.Property#setValue(javax.jcr.Value)
*/
public void setValue(Value value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
setPropertyValue(value, -1);
}
/* (non-Javadoc)
* @see javax.jcr.Property#setValue(javax.jcr.Value[])
*/
public void setValue(Value[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
setPropertyValue(values, -1);
}
/* (non-Javadoc)
* @see javax.jcr.Property#setValue(java.lang.String)
*/
public void setValue(String value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
setPropertyValue(value, -1);
}
/* (non-Javadoc)
* @see javax.jcr.Property#setValue(java.lang.String[])
*/
public void setValue(String[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
setPropertyValue(values, -1);
}
/* (non-Javadoc)
* @see javax.jcr.Property#setValue(java.io.InputStream)
*/
public void setValue(InputStream value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
setPropertyValue(value, -1);
}
/* (non-Javadoc)
* @see javax.jcr.Property#setValue(long)
*/
public void setValue(long value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
setPropertyValue(value, -1);
}
/* (non-Javadoc)
* @see javax.jcr.Property#setValue(double)
*/
public void setValue(double value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
setPropertyValue(value, -1);
}
/* (non-Javadoc)
* @see javax.jcr.Property#setValue(java.util.Calendar)
*/
public void setValue(Calendar value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
setPropertyValue((value == null) ? null : value.getTime(), -1);
}
/* (non-Javadoc)
* @see javax.jcr.Property#setValue(boolean)
*/
public void setValue(boolean value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
setPropertyValue(value, -1);
}
/* (non-Javadoc)
* @see javax.jcr.Property#setValue(javax.jcr.Node)
*/
public void setValue(Node value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
setPropertyValue((value == null) ? null : JCRNodeRef.getNodeRef(value), -1);
}
/* (non-Javadoc)
* @see javax.jcr.Property#getValue()
*/
public Value getValue() throws ValueFormatException, RepositoryException
{
checkSingleValued();
ValueImpl valueImpl = new ValueImpl(session, getType(), getPropertyValue());
// TODO: Could consider returning proxied value implementation (but i don't think is necessary)
return valueImpl;
}
/* (non-Javadoc)
* @see javax.jcr.Property#getValues()
*/
public Value[] getValues() throws ValueFormatException, RepositoryException
{
// get values from node property
checkMultiValued();
Collection values = (Collection)getPropertyValue();
int type = getType();
// construct JCR wrappers
List<Value> jcrValues = new ArrayList<Value>(values.size());
for (Object value : values)
{
// Note: In JCR all null values are stripped
if (value != null)
{
// TODO: Could consider returning proxied value implementation (but i don't think is necessary)
jcrValues.add(new ValueImpl(session, type, value));
}
}
return jcrValues.toArray(new Value[jcrValues.size()]);
}
/* (non-Javadoc)
* @see javax.jcr.Property#getString()
*/
public String getString() throws ValueFormatException, RepositoryException
{
checkSingleValued();
return session.getTypeConverter().stringValue(getPropertyValue());
}
/* (non-Javadoc)
* @see javax.jcr.Property#getStream()
*/
public InputStream getStream() throws ValueFormatException, RepositoryException
{
checkSingleValued();
return session.getTypeConverter().streamValue(getPropertyValue());
}
/* (non-Javadoc)
* @see javax.jcr.Property#getLong()
*/
public long getLong() throws ValueFormatException, RepositoryException
{
checkSingleValued();
return session.getTypeConverter().longValue(getPropertyValue());
}
/* (non-Javadoc)
* @see javax.jcr.Property#getDouble()
*/
public double getDouble() throws ValueFormatException, RepositoryException
{
checkSingleValued();
return session.getTypeConverter().doubleValue(getPropertyValue());
}
/* (non-Javadoc)
* @see javax.jcr.Property#getDate()
*/
public Calendar getDate() throws ValueFormatException, RepositoryException
{
checkSingleValued();
return session.getTypeConverter().dateValue(getPropertyValue());
}
/* (non-Javadoc)
* @see javax.jcr.Property#getBoolean()
*/
public boolean getBoolean() throws ValueFormatException, RepositoryException
{
checkSingleValued();
return session.getTypeConverter().booleanValue(getPropertyValue());
}
/* (non-Javadoc)
* @see javax.jcr.Property#getNode()
*/
public Node getNode() throws ValueFormatException, RepositoryException
{
checkSingleValued();
return session.getTypeConverter().referenceValue(getPropertyValue()).getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Property#getLength()
*/
public long getLength() throws ValueFormatException, RepositoryException
{
checkSingleValued();
return getPropertyLength(getPropertyValue());
}
/* (non-Javadoc)
* @see javax.jcr.Property#getLengths()
*/
public long[] getLengths() throws ValueFormatException, RepositoryException
{
checkMultiValued();
Collection values = (Collection)getPropertyValue();
long[] lengths = new long[values.size()];
int i = 0;
for (Object value : values)
{
lengths[i++] = getPropertyLength(value);
}
return lengths;
}
/* (non-Javadoc)
* @see javax.jcr.Property#getDefinition()
*/
public PropertyDefinition getDefinition() throws RepositoryException
{
PropertyDefinitionImpl propDefImpl = new PropertyDefinitionImpl(session.getTypeManager(), getPropertyDefinition());
return propDefImpl;
}
/* (non-Javadoc)
* @see javax.jcr.Property#getType()
*/
public int getType() throws RepositoryException
{
// TODO: The type should be based on the property value (in the case of undefined required type)
return DataTypeMap.convertDataTypeToPropertyType(getPropertyDefinition().getDataType().getName());
}
/* (non-Javadoc)
* @see javax.jcr.Item#getName()
*/
public String getName() throws RepositoryException
{
return name.toPrefixString(session.getNamespaceResolver());
}
/* (non-Javadoc)
* @see javax.jcr.Item#isNode()
*/
public boolean isNode()
{
return false;
}
/* (non-Javadoc)
* @see javax.jcr.Item#getParent()
*/
public Node getParent() throws ItemNotFoundException, AccessDeniedException, RepositoryException
{
return node.getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Item#getPath()
*/
public String getPath() throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
Path path = nodeService.getPath(node.getNodeRef());
path.append(new JCRPath.SimpleElement(name));
return path.toPrefixString(session.getNamespaceResolver());
}
/* (non-Javadoc)
* @see javax.jcr.Item#getDepth()
*/
public int getDepth() throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
Path path = nodeService.getPath(node.getNodeRef());
// Note: Property is one depth lower than its node
return path.size();
}
/* (non-Javadoc)
* @see javax.jcr.Item#getAncestor(int)
*/
public Item getAncestor(int depth) throws ItemNotFoundException, AccessDeniedException, RepositoryException
{
int propertyDepth = getDepth();
if (depth < 0 || depth > propertyDepth)
{
throw new ItemNotFoundException("Ancestor at depth " + depth + " not found for property " + name);
}
if (depth == propertyDepth)
{
return this.getProxy();
}
else
{
return node.getAncestor(depth -1);
}
}
/* (non-Javadoc)
* @see javax.jcr.Item#isSame(javax.jcr.Item)
*/
public boolean isSame(Item otherItem) throws RepositoryException
{
return getProxy().equals(otherItem);
}
/* (non-Javadoc)
* @see javax.jcr.Item#accept(javax.jcr.ItemVisitor)
*/
public void accept(ItemVisitor visitor) throws RepositoryException
{
visitor.visit(getProxy());
}
/**
* Gets the Node Implementation that contains this property
*
* @return the node implementation
*/
protected NodeImpl getNodeImpl()
{
return node;
}
/**
* Gets the Property Name
*
* @return the property name
*/
protected QName getPropertyName()
{
return name;
}
/**
* Gets the property value
*
* @return the property value
*/
protected Object getPropertyValue()
throws RepositoryException
{
Object value = null;
if (getPropertyDefinition().getDataType().getName().equals(DataTypeDefinition.CONTENT))
{
// Retrieve content reader as value
ContentService contentService = node.session.getRepositoryImpl().getServiceRegistry().getContentService();
value = contentService.getReader(node.getNodeRef(), name);
if (value == null)
{
// TODO: Check - If value is now null, then effectively the property has been removed
throw new RepositoryException("Property " + name + " has been removed.");
}
}
else
{
// TODO: We may need to copy value here...
NodeService nodeService = node.session.getRepositoryImpl().getServiceRegistry().getNodeService();
value = nodeService.getProperty(node.getNodeRef(), name);
if (value == null)
{
// TODO: Check - If value is now null, then effectively the property has been removed
throw new RepositoryException("Property " + name + " has been removed.");
}
// Note: Internal check to ensure that value is single or multi-valued as expected
boolean multiValued = getPropertyDefinition().isMultiValued();
if (multiValued != (value instanceof Collection))
{
throw new RepositoryException("Alfresco value does not match multi-valued definition of " + multiValued);
}
}
return value;
}
/**
* Get Length of a Value
*
* @param value
* @return
* @throws ValueFormatException
* @throws RepositoryException
*/
private long getPropertyLength(Object value) throws ValueFormatException, RepositoryException
{
// Handle streams
if (value instanceof ContentReader)
{
return ((ContentReader)value).getSize();
}
if (value instanceof InputStream)
{
return -1;
}
// Handle all other data types by converting to string
String strValue = (String)DefaultTypeConverter.INSTANCE.convert(String.class, value);
return strValue.length();
}
/**
* Sets a property value
*
* @param value the value to set
* @param type type to explicitly convert to or -1 to convert to property type
* @throws RepositoryException
*/
protected void setPropertyValue(Object value, int type)
throws RepositoryException
{
checkSingleValued();
Object castValue = castValue(value, type);
writeValue(castValue);
}
/**
* Sets a property value
*
* @param values the values to set
* @param type type to explicitly convert to or -1 to convert to property type
* @throws RepositoryException
*/
protected void setPropertyValue(Object[] values, int type)
throws RepositoryException
{
checkMultiValued();
// create collection for multi-valued property
List<Object> castValues = null;
if (values != null)
{
castValues = new ArrayList<Object>(values.length);
for (Object value : values)
{
Object castValue = castValue(value, type);
castValues.add(castValue);
}
}
writeValue(castValues);
}
/**
* Cast value to appropriate type for this property
*
* @param value value to cast
* @param type -1 => cast to property type; otherwise cast to type explicitly provided
* @return the cast value
* @throws RepositoryException
*/
private Object castValue(Object value, int type)
throws RepositoryException
{
// extract raw value if JCR value provided
if (value instanceof Value)
{
value = ValueImpl.getValue((Value)value);
}
// cast value to appropriate type
DataTypeDefinition dataTypeDef = getPropertyDefinition().getDataType();
if (type != -1 && dataTypeDef.getName().equals(DataTypeDefinition.ANY))
{
// attempt cast to explicitly specified type, but only in case where property type can be ANY
QName dataTypeName = DataTypeMap.convertPropertyTypeToDataType(type);
DictionaryService dictionaryService = session.getRepositoryImpl().getServiceRegistry().getDictionaryService();
dataTypeDef = dictionaryService.getDataType(dataTypeName);
if (!dataTypeName.equals(DataTypeDefinition.CONTENT))
{
value = session.getTypeConverter().convert(dataTypeDef, value);
}
}
// special case where binary is converted to inputStream ready for writing via a ContentWriter
if (dataTypeDef.getName().equals(DataTypeDefinition.CONTENT))
{
value = session.getTypeConverter().streamValue(value);
}
return value;
}
/**
* Write the passed value to the property
*
* @param value value to write
* @throws ValueFormatException
*/
private void writeValue(Object value)
throws ValueFormatException
{
// set the property value
if (value instanceof InputStream)
{
// write content
try
{
ContentService contentService = session.getRepositoryImpl().getServiceRegistry().getContentService();
ContentWriter writer = contentService.getWriter(node.getNodeRef(), name, true);
writer.setMimetype(MimetypeMap.MIMETYPE_BINARY);
writer.putContent((InputStream)value);
}
catch(InvalidTypeException e)
{
throw new ValueFormatException(e);
}
}
else
{
// write property value
// Note: In the case of Content properties, this effectively "deletes" the content when the value is null
try
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
nodeService.setProperty(node.getNodeRef(), name, (Serializable)value);
}
catch(TypeConversionException e)
{
throw new ValueFormatException(e);
}
}
}
/**
* Checks that this property is single valued.
*
* @throws ValueFormatException if value is multi-valued
*/
private void checkSingleValued()
throws ValueFormatException
{
if (getPropertyDefinition().isMultiValued())
{
// Expected exception for JSR-170
throw new ValueFormatException("Property " + name + " is multi-valued.");
}
}
/**
* Checks that this property is single valued.
*
* @throws ValueFormatException if value is multi-valued
*/
private void checkMultiValued()
throws ValueFormatException
{
if (!getPropertyDefinition().isMultiValued())
{
// Expected exception for JSR-170
throw new ValueFormatException("Property " + name + " is single-valued.");
}
}
/**
* Gets the Property Data Type
*
* @return the (JCR) data type
*/
private org.alfresco.service.cmr.dictionary.PropertyDefinition getPropertyDefinition()
{
DictionaryService dictionary = session.getRepositoryImpl().getServiceRegistry().getDictionaryService();
return dictionary.getProperty(name);
}
@Override
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (!(obj instanceof PropertyImpl))
{
return false;
}
PropertyImpl other = (PropertyImpl)obj;
return this.name.equals(other.name);
}
@Override
public int hashCode()
{
return name.hashCode();
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import java.util.List;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import org.alfresco.jcr.util.AbstractRangeIterator;
/**
* Alfresco implementation of a Property Iterator
*
* @author David Caruana
*/
public class PropertyListIterator extends AbstractRangeIterator
implements PropertyIterator
{
private List<PropertyImpl> properties;
/**
* Construct
*
* @param context session context
* @param properties property list
*/
public PropertyListIterator(List<PropertyImpl> properties)
{
this.properties = properties;
}
/* (non-Javadoc)
* @see javax.jcr.PropertyIterator#nextProperty()
*/
public Property nextProperty()
{
long position = skip();
PropertyImpl propertyImpl = properties.get((int)position);
return propertyImpl.getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.RangeIterator#getSize()
*/
public long getSize()
{
return properties.size();
}
/* (non-Javadoc)
* @see java.util.Iterator#next()
*/
public Object next()
{
return nextProperty();
}
}

View File

@@ -0,0 +1,193 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.ValueFormatException;
import org.alfresco.jcr.session.SessionImpl;
import org.alfresco.jcr.util.JCRProxyFactory;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
/**
* Alfresco implementation of JCR Value Factory
*
* @author David Caruana
*
*/
public class ValueFactoryImpl implements ValueFactory
{
private SessionImpl session;
private ValueFactory proxy = null;
/**
* Construct
*
* @param session
*/
public ValueFactoryImpl(SessionImpl session)
{
this.session = session;
}
/**
* Get proxied JCR Value Factory
*
* @return
*/
public ValueFactory getProxy()
{
if (proxy == null)
{
proxy = (ValueFactory)JCRProxyFactory.create(this, ValueFactory.class, session);
}
return proxy;
}
/* (non-Javadoc)
* @see javax.jcr.ValueFactory#createValue(java.lang.String, int)
*/
public Value createValue(String value, int type) throws ValueFormatException
{
Value createdValue = null;
try
{
switch(type)
{
case PropertyType.STRING:
createdValue = createValue(session.getTypeConverter().stringValue(value));
break;
case PropertyType.LONG:
createdValue = createValue(session.getTypeConverter().longValue(value));
break;
case PropertyType.DOUBLE:
createdValue = createValue(session.getTypeConverter().doubleValue(value));
break;
case PropertyType.BOOLEAN:
createdValue = createValue(session.getTypeConverter().booleanValue(value));
break;
case PropertyType.DATE:
createdValue = new ValueImpl(session, PropertyType.DATE, session.getTypeConverter().convert(Date.class, value));
break;
case PropertyType.BINARY:
createdValue = createValue(session.getTypeConverter().streamValue(value));
break;
case PropertyType.REFERENCE:
createdValue = new ValueImpl(session, PropertyType.REFERENCE, session.getTypeConverter().referenceValue(value));
break;
case PropertyType.NAME:
QName name = session.getTypeConverter().convert(QName.class, value);
createdValue = new ValueImpl(session, PropertyType.NAME, name);
break;
case PropertyType.PATH:
Path path = session.getTypeConverter().convert(Path.class, value);
createdValue = new ValueImpl(session, PropertyType.PATH, path);
break;
default:
throw new ValueFormatException("Cannot create value of type " + type);
}
}
catch(RepositoryException e)
{
// Should this method also throw repository exception
throw new ValueFormatException("Failed to create value " + value + " of type " + type, e);
}
return createdValue;
}
/* (non-Javadoc)
* @see javax.jcr.ValueFactory#createValue(java.lang.String)
*/
public Value createValue(String value)
{
return new ValueImpl(session, PropertyType.STRING, value);
}
/* (non-Javadoc)
* @see javax.jcr.ValueFactory#createValue(long)
*/
public Value createValue(long value)
{
return new ValueImpl(session, PropertyType.LONG, value);
}
/* (non-Javadoc)
* @see javax.jcr.ValueFactory#createValue(double)
*/
public Value createValue(double value)
{
return new ValueImpl(session, PropertyType.DOUBLE, value);
}
/* (non-Javadoc)
* @see javax.jcr.ValueFactory#createValue(boolean)
*/
public Value createValue(boolean value)
{
return new ValueImpl(session, PropertyType.BOOLEAN, value);
}
/* (non-Javadoc)
* @see javax.jcr.ValueFactory#createValue(java.util.Calendar)
*/
public Value createValue(Calendar value)
{
return new ValueImpl(session, PropertyType.DATE, value.getTime());
}
/* (non-Javadoc)
* @see javax.jcr.ValueFactory#createValue(java.io.InputStream)
*/
public Value createValue(InputStream value)
{
return new ValueImpl(session, PropertyType.BINARY, value);
}
/* (non-Javadoc)
* @see javax.jcr.ValueFactory#createValue(javax.jcr.Node)
*/
public Value createValue(Node value) throws RepositoryException
{
if (value == null)
{
throw new RepositoryException("Node value must not be null");
}
// TODO: refer to ContentModel Constants
Property protocol = value.getProperty("sys:store-protocol");
Property identifier = value.getProperty("sys:store-identifier");
Property uuid = value.getProperty("sys:node-uuid");
// construct a node reference
NodeRef ref = new NodeRef(new StoreRef(protocol.getString(), identifier.getString()), uuid.getString());
return new ValueImpl(session, PropertyType.REFERENCE, ref);
}
}

View File

@@ -0,0 +1,321 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item;
import java.io.InputStream;
import java.util.Calendar;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import org.alfresco.jcr.session.SessionImpl;
import org.alfresco.jcr.util.JCRProxyFactory;
import org.alfresco.service.cmr.repository.ContentReader;
/**
* Alfresco implementation of JCR Value
*
* @author David Caruana
*/
public class ValueImpl implements Value
{
private enum ValueState {Stream, Value, None};
private ValueState state = ValueState.None;
private SessionImpl session;
private int datatype;
private Object value;
private InputStream stream = null;
private Value proxy;
/**
* Constuct
*
* @param value value to wrap
*/
public ValueImpl(SessionImpl session, int datatype, Object value)
{
this.session = session;
this.datatype = datatype;
this.value = value;
}
/**
* Create a proxied JCR Value
*
* @return the proxied value
*/
public Value getProxy()
{
if (proxy == null)
{
proxy = (Value)JCRProxyFactory.create(this, Value.class, session);
}
return proxy;
}
/* (non-Javadoc)
* @see javax.jcr.Value#getString()
*/
public String getString() throws ValueFormatException, IllegalStateException, RepositoryException
{
isValidState(ValueState.Value);
String typedValue = session.getTypeConverter().stringValue(getInternalValue());
value = typedValue;
enterState(ValueState.Value);
return typedValue;
}
/* (non-Javadoc)
* @see javax.jcr.Value#getStream()
*/
public InputStream getStream() throws IllegalStateException, RepositoryException
{
isValidState(ValueState.Stream);
if (stream == null)
{
stream = session.getTypeConverter().streamValue(value);
}
enterState(ValueState.Stream);
return stream;
}
/* (non-Javadoc)
* @see javax.jcr.Value#getLong()
*/
public long getLong() throws ValueFormatException, IllegalStateException, RepositoryException
{
isValidState(ValueState.Value);
long typedValue = session.getTypeConverter().longValue(getInternalValue());
value = typedValue;
enterState(ValueState.Value);
return typedValue;
}
/* (non-Javadoc)
* @see javax.jcr.Value#getDouble()
*/
public double getDouble() throws ValueFormatException, IllegalStateException, RepositoryException
{
isValidState(ValueState.Value);
double typedValue = session.getTypeConverter().doubleValue(getInternalValue());
value = typedValue;
enterState(ValueState.Value);
return typedValue;
}
/* (non-Javadoc)
* @see javax.jcr.Value#getDate()
*/
public Calendar getDate() throws ValueFormatException, IllegalStateException, RepositoryException
{
isValidState(ValueState.Value);
Calendar typedValue = session.getTypeConverter().dateValue(getInternalValue());
value = typedValue.getTime();
enterState(ValueState.Value);
return typedValue;
}
/* (non-Javadoc)
* @see javax.jcr.Value#getBoolean()
*/
public boolean getBoolean() throws ValueFormatException, IllegalStateException, RepositoryException
{
isValidState(ValueState.Value);
boolean typedValue = session.getTypeConverter().booleanValue(getInternalValue());
value = typedValue;
enterState(ValueState.Value);
return typedValue;
}
/* (non-Javadoc)
* @see javax.jcr.Value#getType()
*/
public int getType()
{
return datatype;
}
/**
* Get value
*
* @param value the value wrapper to extract from
* @return the value
*/
public static Object getValue(Value value) throws RepositoryException
{
Object objValue = null;
int valueType = value.getType();
switch(valueType)
{
case PropertyType.STRING:
case PropertyType.NAME:
case PropertyType.PATH:
objValue = value.getString();
break;
case PropertyType.LONG:
objValue = value.getLong();
break;
case PropertyType.DOUBLE:
objValue = value.getDouble();
break;
case PropertyType.BOOLEAN:
objValue = value.getBoolean();
break;
case PropertyType.DATE:
objValue = value.getDate();
break;
case PropertyType.BINARY:
objValue = value.getStream();
break;
default:
// Note: just take the internal value
objValue = ((ValueImpl)value).value;
break;
}
return objValue;
}
/**
* Get typed value
*
* @param value the value to extract from
* @return the wrapped object
*/
public static Object getValue(JCRTypeConverter typeConverter, int requiredType, Value value) throws RepositoryException
{
Object objValue = null;
switch(requiredType)
{
case PropertyType.STRING:
objValue = value.getString();
break;
case PropertyType.LONG:
objValue = value.getLong();
break;
case PropertyType.DOUBLE:
objValue = value.getDouble();
break;
case PropertyType.BOOLEAN:
objValue = value.getBoolean();
break;
case PropertyType.DATE:
objValue = value.getDate();
break;
case PropertyType.BINARY:
objValue = value.getStream();
break;
case PropertyType.NAME:
objValue = typeConverter.nameValue(ValueImpl.getValue(value));
break;
case PropertyType.PATH:
objValue = typeConverter.pathValue(ValueImpl.getValue(value));
break;
default:
throw new ValueFormatException("Unsupported Value Type " + requiredType);
}
return objValue;
}
/**
* Retrieve Value
*
* Note: When retrieving non stream values against a backed stream, the content reader
* has to be re-created.
*
* @return the value
*/
private Object getInternalValue()
{
if (value instanceof ContentReader && state == ValueState.Value)
{
value = ((ContentReader)value).getReader();
}
return value;
}
/**
* Check for valid state
*
* @param state the state to check
* @throws IllegalStateException state is not valid
*/
private void isValidState(ValueState state)
{
if (this.state != ValueState.None && this.state != state)
{
throw new IllegalStateException("This value has already been retrieved as a " + state + " and cannot be retrieved as a " + ValueState.Stream + ".");
}
}
/**
* Enter state
*
* @param state the state to enter
*/
private void enterState(ValueState state)
{
this.state = state;
}
@Override
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (!(obj instanceof ValueImpl))
{
return false;
}
ValueImpl other = (ValueImpl)obj;
// check data type first
if (datatype != other.datatype)
{
return false;
}
// handle case where values are content streams
if (value instanceof ContentReader)
{
String thisUrl = ((ContentReader)value).getContentUrl();
String otherUrl = ((ContentReader)other).getContentUrl();
return thisUrl.equals(otherUrl);
}
// handle other value types
return value.equals(other.value);
}
@Override
public int hashCode()
{
return value.hashCode() * 32 + datatype;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item.property;
import javax.jcr.RepositoryException;
import org.alfresco.jcr.dictionary.JCRNamespace;
import org.alfresco.jcr.item.NodeImpl;
import org.alfresco.jcr.item.PropertyImpl;
import org.alfresco.service.namespace.QName;
/**
* Implementation for mix:lockable lockIsDeep property
*
* @author David Caruana
*/
public class JCRLockIsDeepProperty extends PropertyImpl
{
public static QName PROPERTY_NAME = QName.createQName(JCRNamespace.JCR_URI, "lockIsDeep");
/**
* Construct
*
* @param node
*/
public JCRLockIsDeepProperty(NodeImpl node)
{
super(node, PROPERTY_NAME);
}
@Override
protected Object getPropertyValue() throws RepositoryException
{
return false;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item.property;
import javax.jcr.RepositoryException;
import org.alfresco.jcr.dictionary.JCRNamespace;
import org.alfresco.jcr.item.NodeImpl;
import org.alfresco.jcr.item.PropertyImpl;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
/**
* Implementation for mix:lockable lockOwner property
*
* @author David Caruana
*/
public class JCRLockOwnerProperty extends PropertyImpl
{
public static QName PROPERTY_NAME = QName.createQName(JCRNamespace.JCR_URI, "lockOwner");
/**
* Construct
*
* @param node
*/
public JCRLockOwnerProperty(NodeImpl node)
{
super(node, PROPERTY_NAME);
}
@Override
protected Object getPropertyValue() throws RepositoryException
{
NodeImpl nodeImpl = getNodeImpl();
NodeService nodeService = nodeImpl.getSessionImpl().getRepositoryImpl().getServiceRegistry().getNodeService();
String lockOwner = (String)nodeService.getProperty(nodeImpl.getNodeRef(), ContentModel.PROP_LOCK_OWNER);
return lockOwner;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item.property;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.jcr.RepositoryException;
import org.alfresco.jcr.dictionary.JCRNamespace;
import org.alfresco.jcr.dictionary.NodeTypeImpl;
import org.alfresco.jcr.item.NodeImpl;
import org.alfresco.jcr.item.PropertyImpl;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
/**
* Implementation for nt:base primaryType property
*
* @author David Caruana
*/
public class JCRMixinTypesProperty extends PropertyImpl
{
public static QName PROPERTY_NAME = QName.createQName(JCRNamespace.JCR_URI, "mixinTypes");
/**
* Construct
*
* @param node
*/
public JCRMixinTypesProperty(NodeImpl node)
{
super(node, PROPERTY_NAME);
}
@Override
protected Object getPropertyValue() throws RepositoryException
{
// get aspects from node
NodeImpl nodeImpl = getNodeImpl();
NodeService nodeService = nodeImpl.getSessionImpl().getRepositoryImpl().getServiceRegistry().getNodeService();
Set<QName> aspects = nodeService.getAspects(nodeImpl.getNodeRef());
// resolve against session namespace prefix resolver
List<String> aspectNames = new ArrayList<String>(aspects.size() + 1);
for (QName aspect : aspects)
{
aspectNames.add(aspect.toPrefixString(nodeImpl.getSessionImpl().getNamespaceResolver()));
}
// add JCR referenceable
aspectNames.add(NodeTypeImpl.MIX_REFERENCEABLE.toPrefixString(nodeImpl.getSessionImpl().getNamespaceResolver()));
return aspectNames;
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item.property;
import javax.jcr.RepositoryException;
import org.alfresco.jcr.dictionary.JCRNamespace;
import org.alfresco.jcr.item.NodeImpl;
import org.alfresco.jcr.item.PropertyImpl;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
/**
* Implementation for nt:base primaryType property
*
* @author David Caruana
*/
public class JCRPrimaryTypeProperty extends PropertyImpl
{
public static QName PROPERTY_NAME = QName.createQName(JCRNamespace.JCR_URI, "primaryType");
/**
* Construct
*
* @param node
*/
public JCRPrimaryTypeProperty(NodeImpl node)
{
super(node, PROPERTY_NAME);
}
@Override
protected Object getPropertyValue() throws RepositoryException
{
NodeImpl nodeImpl = getNodeImpl();
NodeService nodeService = nodeImpl.getSessionImpl().getRepositoryImpl().getServiceRegistry().getNodeService();
QName type = nodeService.getType(nodeImpl.getNodeRef());
return type.toPrefixString(nodeImpl.getSessionImpl().getNamespaceResolver());
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item.property;
import javax.jcr.RepositoryException;
import org.alfresco.jcr.dictionary.JCRNamespace;
import org.alfresco.jcr.item.NodeImpl;
import org.alfresco.jcr.item.PropertyImpl;
import org.alfresco.service.namespace.QName;
/**
* Implementation for mix:referenceable uuid property
* @author David Caruana
*
*/
public class JCRUUIDProperty extends PropertyImpl
{
public static QName PROPERTY_NAME = QName.createQName(JCRNamespace.JCR_URI, "uuid");
/**
* Construct
*
* @param node
*/
public JCRUUIDProperty(NodeImpl node)
{
super(node, PROPERTY_NAME);
}
@Override
protected Object getPropertyValue() throws RepositoryException
{
NodeImpl node = getNodeImpl();
return node.getNodeRef().getId();
}
}

View File

@@ -0,0 +1,204 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* 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.
*/
package org.alfresco.jcr.item.property;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.jcr.PathNotFoundException;
import org.alfresco.jcr.item.NodeImpl;
import org.alfresco.jcr.item.PropertyImpl;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNamePattern;
/**
* Responsible for resolving properties on Nodes
*
* @author David Caruana
*/
public class PropertyResolver
{
private static Map<QName, QName> virtualProperties = new HashMap<QName, QName>();
static
{
virtualProperties.put(JCRUUIDProperty.PROPERTY_NAME, null);
virtualProperties.put(JCRPrimaryTypeProperty.PROPERTY_NAME, null);
virtualProperties.put(JCRMixinTypesProperty.PROPERTY_NAME, null);
virtualProperties.put(JCRLockOwnerProperty.PROPERTY_NAME, ContentModel.ASPECT_LOCKABLE);
virtualProperties.put(JCRLockIsDeepProperty.PROPERTY_NAME, ContentModel.ASPECT_LOCKABLE);
// TODO: mix:versionable
}
/**
* Create Property List for all properties of this node
*
* @return list of properties (null properties are filtered)
*/
public static List<PropertyImpl> createProperties(NodeImpl node, QNamePattern pattern)
{
// Create list of properties from node itself
NodeService nodeService = node.getSessionImpl().getRepositoryImpl().getServiceRegistry().getNodeService();
Map<QName, Serializable> properties = nodeService.getProperties(node.getNodeRef());
List<PropertyImpl> propertyList = new ArrayList<PropertyImpl>(properties.size());
for (Map.Entry<QName, Serializable> entry : properties.entrySet())
{
QName propertyName = entry.getKey();
if (pattern == null || pattern.isMatch(propertyName))
{
Serializable value = entry.getValue();
if (value != null)
{
PropertyImpl property = new PropertyImpl(node, propertyName);
propertyList.add(property);
}
}
}
// Add JCR properties
for (Map.Entry<QName, QName> virtualProperty : virtualProperties.entrySet())
{
boolean addJCRProperty = false;
if (virtualProperty.getValue() == null)
{
addJCRProperty = true;
}
else
{
addJCRProperty = nodeService.hasAspect(node.getNodeRef(), virtualProperty.getValue());
}
if (addJCRProperty && (pattern == null || pattern.isMatch(virtualProperty.getKey())))
{
propertyList.add(createVirtualProperty(node, virtualProperty.getKey()));
}
}
return propertyList;
}
/**
* Create property for the given named property
*
* @param node
* @param propertyName
* @return
* @throws PathNotFoundException
*/
public static PropertyImpl createProperty(NodeImpl node, QName propertyName)
throws PathNotFoundException
{
// has a JCR property been requested that is not persisted in Alfresco repository?
if (hasVirtualProperty(node, propertyName))
{
return createVirtualProperty(node, propertyName);
}
// has a property been requested that actually exists?
NodeService nodeService = node.getSessionImpl().getRepositoryImpl().getServiceRegistry().getNodeService();
Serializable value = nodeService.getProperty(node.getNodeRef(), propertyName);
if (value == null)
{
throw new PathNotFoundException("Property path " + propertyName + " not found from node " + node.getNodeRef());
}
// construct property wrapper
PropertyImpl propertyImpl = new PropertyImpl(node, propertyName);
return propertyImpl;
}
private static PropertyImpl createVirtualProperty(NodeImpl node, QName propertyName)
{
if (propertyName.equals(JCRUUIDProperty.PROPERTY_NAME))
{
return new JCRUUIDProperty(node);
}
if (propertyName.equals(JCRPrimaryTypeProperty.PROPERTY_NAME))
{
return new JCRPrimaryTypeProperty(node);
}
if (propertyName.equals(JCRMixinTypesProperty.PROPERTY_NAME))
{
return new JCRMixinTypesProperty(node);
}
if (propertyName.equals(JCRLockOwnerProperty.PROPERTY_NAME))
{
return new JCRLockOwnerProperty(node);
}
if (propertyName.equals(JCRLockIsDeepProperty.PROPERTY_NAME))
{
return new JCRLockIsDeepProperty(node);
}
return null;
}
/**
* Check for existence of Property on specified Node
*
* @param node
* @param propertyName
* @return
*/
public static boolean hasProperty(NodeImpl node, QName propertyName)
{
if (hasVirtualProperty(node, propertyName))
{
return true;
}
NodeService nodeService = node.getSessionImpl().getRepositoryImpl().getServiceRegistry().getNodeService();
Serializable value = nodeService.getProperty(node.getNodeRef(), propertyName);
return value != null;
}
private static boolean hasVirtualProperty(NodeImpl node, QName propertyName)
{
// is this a virtual property
if (virtualProperties.containsKey(propertyName))
{
// is this a virtual property attached to a specific aspect
QName aspect = virtualProperties.get(propertyName);
if (aspect == null)
{
// it's supported on all types
return true;
}
// is the aspect attached to the node
NodeService nodeService = node.getSessionImpl().getRepositoryImpl().getServiceRegistry().getNodeService();
return nodeService.hasAspect(node.getNodeRef(), aspect);
}
// no, it's not even a virtual property
return false;
}
}