package org.argeo.api.gcr;
+import java.util.List;
import java.util.Map;
+import java.util.Optional;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
* ATTRIBUTES OPERATIONS
*/
- <A> A get(QName key, Class<A> clss) throws IllegalArgumentException;
+ <A> Optional<A> get(QName key, Class<A> clss);
default Object get(String key) {
if (key.indexOf(':') >= 0)
return remove(new QName(XMLConstants.NULL_NS_URI, key, XMLConstants.DEFAULT_NS_PREFIX));
}
+ Class<?> getType(QName key);
+
+ boolean isMultiple(QName key);
+
+ <A> Optional<List<A>> getMultiple(QName key, Class<A> clss);
+
+ default <A> List<A> getMultiple(QName key) {
+ Class<A> type;
+ try {
+ type = (Class<A>) getType(key);
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("Requested type is not the default type");
+ }
+ Optional<List<A>> res = getMultiple(key, type);
+ if (res == null)
+ return null;
+ else {
+ if (res.isEmpty())
+ throw new IllegalStateException("Metadata " + key + " is not availabel as list of type " + type);
+ return res.get();
+ }
+ }
+
/*
* CONTENT OPERATIONS
*/
// private final UUID uuid;
public ContentName(String namespaceURI, String localPart, NamespaceContext nsContext) {
- this(namespaceURI, localPart, nsContext.getPrefix(namespaceURI));
+ super(namespaceURI, localPart, checkPrefix(nsContext, namespaceURI));
}
- protected ContentName(String namespaceURI, String localPart, String prefix) {
- super(namespaceURI, localPart, prefix);
+ private static String checkPrefix(NamespaceContext nsContext, String namespaceURI) {
+ Objects.requireNonNull(nsContext, "Namespace context cannot be null");
+ Objects.requireNonNull(namespaceURI, "Namespace URI cannot be null");
+ String prefix = nsContext.getNamespaceURI(namespaceURI);
if (prefix == null)
- throw new IllegalArgumentException("Prefix annot be null");
+ throw new IllegalStateException("No prefix found for " + namespaceURI + " from context " + nsContext);
+ return prefix;
+ }
+
+ ContentName(String namespaceURI, String localPart, String prefix) {
+ super(namespaceURI, localPart, prefix);
}
public ContentName(String localPart) {
- this(XMLConstants.NULL_NS_URI, localPart, XMLConstants.DEFAULT_NS_PREFIX);
+ super(XMLConstants.NULL_NS_URI, localPart, XMLConstants.DEFAULT_NS_PREFIX);
}
public ContentName(QName qName, NamespaceContext nsContext) {
public interface ContentNameSupplier extends Supplier<ContentName>, NamespaceContext {
String name();
+ String getNamespaceURI();
+
+ String getDefaultPrefix();
+
@Override
default ContentName get() {
return toContentName();
return new ContentName(getNamespaceURI(), camlName, this);
}
- default String getNamespaceURI() {
- return XMLConstants.NULL_NS_URI;
- }
-
- default String getDefaultPrefix() {
- return XMLConstants.DEFAULT_NS_PREFIX;
- }
+// default String getNamespaceURI() {
+// return XMLConstants.NULL_NS_URI;
+// }
+//
+// default String getDefaultPrefix() {
+// return XMLConstants.DEFAULT_NS_PREFIX;
+// }
// static ContentName toContentName(String namespaceURI, String localName, String prefix) {
// CompositeString cs = new CompositeString(localName);
import java.time.format.DateTimeParseException;
import java.util.UUID;
+import javax.xml.XMLConstants;
+
/**
* Minimal standard attribute types that MUST be supported. All related classes
* belong to java.base and can be implicitly derived form a given
* <code>String<code>.
*/
-public enum CrAttributeType {
+public enum CrAttributeType implements ContentNameSupplier {
BOOLEAN(Boolean.class, new BooleanFormatter()), //
INTEGER(Integer.class, new IntegerFormatter()), //
LONG(Long.class, new LongFormatter()), //
DOUBLE(Double.class, new DoubleFormatter()), //
// we do not support short and float, like recent additions to Java
// (e.g. optional primitives)
- INSTANT(Instant.class, new InstantFormatter()), //
+ DATE_TIME(Instant.class, new InstantFormatter()), //
UUID(UUID.class, new UuidFormatter()), //
- URI(URI.class, new UriFormatter()), //
+ ANY_URI(URI.class, new UriFormatter()), //
STRING(String.class, new StringFormatter()), //
;
+ private final Class<?> clss;
+ private final AttributeFormatter<?> formatter;
+
private <T> CrAttributeType(Class<T> clss, AttributeFormatter<T> formatter) {
this.clss = clss;
this.formatter = formatter;
}
- private final Class<?> clss;
- private final AttributeFormatter<?> formatter;
-
public Class<?> getClss() {
return clss;
}
return formatter;
}
+ @Override
+ public String getDefaultPrefix() {
+ if (equals(UUID))
+ return CrName.CR_DEFAULT_PREFIX;
+ else
+ return "xs";
+ }
+
+ @Override
+ public String getNamespaceURI() {
+ if (equals(UUID))
+ return CrName.CR_NAMESPACE_URI;
+ else
+ return XMLConstants.W3C_XML_SCHEMA_NS_URI;
+ }
+
public static Object parse(String str) {
if (str == null)
throw new IllegalArgumentException("String cannot be null");
// silent
}
try {
- return INSTANT.getFormatter().parse(str);
+ return DATE_TIME.getFormatter().parse(str);
} catch (IllegalArgumentException e) {
// silent
}
// silent
}
try {
- java.net.URI uri = (java.net.URI) URI.getFormatter().parse(str);
+ java.net.URI uri = (java.net.URI) ANY_URI.getFormatter().parse(str);
if (uri.getScheme() != null)
return uri;
String path = uri.getPath();
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import javax.xml.namespace.QName;
public abstract class AbstractContent extends AbstractMap<QName, Object> implements Content {
+ /*
+ * ATTRIBUTES OPERATIONS
+ */
+ protected abstract Iterable<QName> keys();
+
+ protected abstract void removeAttr(QName key);
+
@Override
public Set<Entry<QName, Object>> entrySet() {
-// Set<Entry<String, Object>> result = new HashSet<>();
-// for (String key : keys()) {
-// Entry<String, Object> entry = new Entry<String, Object>() {
-//
-// @Override
-// public String getKey() {
-// return key;
-// }
-//
-// @Override
-// public Object getValue() {
-// return get(key, Object.class);
-// }
-//
-// @Override
-// public Object setValue(Object value) {
-// throw new UnsupportedOperationException();
-// }
-//
-// };
-// result.add(entry);
-// }
Set<Entry<QName, Object>> result = new AttrSet();
return result;
}
- protected abstract Iterable<QName> keys();
+ @Override
+ public Class<?> getType(QName key) {
+ return String.class;
+ }
- protected abstract void removeAttr(QName key);
+ @Override
+ public boolean isMultiple(QName key) {
+ return false;
+ }
+
+ @Override
+ public <A> Optional<List<A>> getMultiple(QName key, Class<A> clss) {
+ Object value = get(key);
+ if (value == null)
+ return null;
+ if (value instanceof List) {
+ try {
+ List<A> res = (List<A>) value;
+ return Optional.of(res);
+ } catch (ClassCastException e) {
+ List<A> res = new ArrayList<>();
+ List<?> lst = (List<?>) value;
+ try {
+ for (Object o : lst) {
+ A item = (A) o;
+ res.add(item);
+ }
+ return Optional.of(res);
+ } catch (ClassCastException e1) {
+ return Optional.empty();
+ }
+ }
+ } else {// singleton
+ try {
+ A res = (A) value;
+ return Optional.of(Collections.singletonList(res));
+ } catch (ClassCastException e) {
+ return Optional.empty();
+ }
+ }
+ }
+
+ /*
+ * CONTENT OPERATIONS
+ */
@Override
public String getPath() {
public Entry<QName, Object> next() {
key = keys.next();
// TODO check type
- Object value = get(key, Object.class);
- AbstractMap.SimpleEntry<QName, Object> entry = new SimpleEntry<>(key, value);
+ Optional<?> value = get(key, Object.class);
+ assert !value.isEmpty();
+ AbstractMap.SimpleEntry<QName, Object> entry = new SimpleEntry<>(key, value.get());
return entry;
}
import java.util.Calendar;
import java.util.Iterator;
+import java.util.Optional;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
}
@Override
- public <A> A get(QName key, Class<A> clss) {
+ public <A> Optional<A> get(QName key, Class<A> clss) {
if (isDefaultAttrTypeRequested(clss)) {
- return (A) get(jcrNode, key.toString());
+ return Optional.of((A) get(jcrNode, key.toString()));
}
- return (A) Jcr.get(jcrNode, key.toString());
+ return Optional.of((A) Jcr.get(jcrNode, key.toString()));
}
@Override
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import javax.xml.namespace.QName;
*/
@Override
- public <A> A get(QName key, Class<A> clss) {
+ public <A> Optional<A> get(QName key, Class<A> clss) {
Object value;
try {
// We need to add user: when accessing via Files#getAttribute
} catch (IOException e) {
throw new ContentResourceException("Cannot retrieve attribute " + key + " for " + path, e);
}
+ A res = null;
if (value instanceof FileTime) {
if (clss.isAssignableFrom(FileTime.class))
- return (A) value;
+ res = (A) value;
Instant instant = ((FileTime) value).toInstant();
if (Object.class.isAssignableFrom(clss)) {// plain object requested
- return (A) instant;
+ res = (A) instant;
}
// TODO perform trivial file conversion to other formats
}
if (value instanceof byte[]) {
- return (A) new String((byte[]) value, StandardCharsets.UTF_8);
+ res = (A) new String((byte[]) value, StandardCharsets.UTF_8);
}
- return (A) value;
+ if (res == null)
+ try {
+ res = (A) value;
+ } catch (ClassCastException e) {
+ return Optional.empty();
+ }
+ return Optional.of(res);
}
@Override
import java.util.HashSet;
import java.util.Iterator;
+import java.util.Optional;
import java.util.Set;
import javax.xml.XMLConstants;
}
@Override
- public <A> A get(QName key, Class<A> clss) {
+ public <A> Optional<A> get(QName key, Class<A> clss) {
String namespaceUriOrNull = XMLConstants.NULL_NS_URI.equals(key.getNamespaceURI()) ? null
: key.getNamespaceURI();
if (element.hasAttributeNS(namespaceUriOrNull, key.getLocalPart())) {
String value = element.getAttributeNS(namespaceUriOrNull, key.getLocalPart());
if (clss.isAssignableFrom(String.class))
- return (A) value;
+ return Optional.of((A) value);
else
- throw new IllegalArgumentException();
+ return Optional.empty();
} else
return null;
}
value.toString());
return previous;
}
+
+
@Override
public boolean hasText() {