blob: 1000d4ec08322adb1e4b466b29e115dd620d22b1 [file] [log] [blame]
/*
* 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.
*/
package org.apache.sling.jcr.resource.internal.helper.jcr;
import static javax.jcr.Property.JCR_CONTENT;
import static javax.jcr.Property.JCR_CREATED;
import static javax.jcr.Property.JCR_DATA;
import static javax.jcr.Property.JCR_ENCODING;
import static javax.jcr.Property.JCR_FROZEN_PRIMARY_TYPE;
import static javax.jcr.Property.JCR_LAST_MODIFIED;
import static javax.jcr.Property.JCR_MIMETYPE;
import static javax.jcr.nodetype.NodeType.NT_FILE;
import static javax.jcr.nodetype.NodeType.NT_FROZEN_NODE;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.ValueFormatException;
import org.apache.sling.api.resource.ResourceMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class JcrNodeResourceMetadata extends ResourceMetadata {
private static final long serialVersionUID = 1L;
/** default log */
private static final Logger LOGGER = LoggerFactory.getLogger(JcrNodeResource.class);
private final Node node;
private Node contentNode;
private boolean nodePromotionChecked = false;
private long creationTime = -1;
private boolean populated = false;
public JcrNodeResourceMetadata(final Node inNode) {
this.node = inNode;
}
private Node promoteNode() {
// check stuff for nt:file nodes
try {
if ((!nodePromotionChecked) &&
(node.isNodeType(NT_FILE) ||
(node.isNodeType(NT_FROZEN_NODE) &&
node.getProperty(JCR_FROZEN_PRIMARY_TYPE).getString().equals(NT_FILE)))) {
creationTime = node.getProperty(JCR_CREATED).getLong();
// continue our stuff with the jcr:content node
// which might be nt:resource, which we support below
// if the node is new, the content node might not exist yet
if (!node.isNew() || node.hasNode(JCR_CONTENT)) {
contentNode = node.getNode(JCR_CONTENT);
}
nodePromotionChecked = true;
}
} catch (final RepositoryException re) {
report(re);
}
return contentNode != null ? contentNode : node;
}
private void report(final RepositoryException re) {
String nodePath = "<unknown node path>";
try {
nodePath = contentNode != null ? contentNode.getPath() : node.getPath();
} catch (RepositoryException e) {
// ignore
}
LOGGER.info("setMetaData: Problem extracting metadata information for " + nodePath, re);
}
@Override
public Object get(final Object key) {
final Object result = super.get(key);
if (result != null) {
return result;
}
if (CREATION_TIME.equals(key)) {
promoteNode();
internalPut(CREATION_TIME, creationTime);
return creationTime;
} else if (CONTENT_TYPE.equals(key)) {
String contentType = null;
final Node targetNode = promoteNode();
try {
if (targetNode.hasProperty(JCR_MIMETYPE)) {
contentType = targetNode.getProperty(JCR_MIMETYPE).getString();
}
} catch (final RepositoryException re) {
report(re);
}
internalPut(CONTENT_TYPE, contentType);
return contentType;
} else if (CHARACTER_ENCODING.equals(key)) {
String characterEncoding = null;
final Node targetNode = promoteNode();
try {
if (targetNode.hasProperty(JCR_ENCODING)) {
characterEncoding = targetNode.getProperty(JCR_ENCODING).getString();
}
} catch (final RepositoryException re) {
report(re);
}
internalPut(CHARACTER_ENCODING, characterEncoding);
return characterEncoding;
} else if (MODIFICATION_TIME.equals(key)) {
long modificationTime = -1;
final Node targetNode = promoteNode();
try {
if (targetNode.hasProperty(JCR_LAST_MODIFIED)) {
// We don't check node type, so JCR_LASTMODIFIED might not be a long
final Property prop = targetNode.getProperty(JCR_LAST_MODIFIED);
try {
modificationTime = prop.getLong();
} catch (final ValueFormatException vfe) {
LOGGER.debug("Property {} cannot be converted to a long, ignored ({})",
prop.getPath(), vfe);
}
}
} catch (final RepositoryException re) {
report(re);
}
internalPut(MODIFICATION_TIME, modificationTime);
return modificationTime;
} else if (CONTENT_LENGTH.equals(key)) {
long contentLength = -1;
final Node targetNode = promoteNode();
try {
// if the node has a jcr:data property, use that property
if (targetNode.hasProperty(JCR_DATA)) {
final Property prop = targetNode.getProperty(JCR_DATA);
contentLength = JcrItemResource.getContentLength(prop);
} else {
// otherwise try to follow default item trail
Item item = getPrimaryItem(targetNode);
while (item != null && item.isNode()) {
item = getPrimaryItem((Node) item);
}
if (item != null) {
final Property data = (Property) item;
// set the content length property as a side effect
// for resources which are not nt:file based and whose
// data is not in jcr:content/jcr:data this will lazily
// set the correct content length
contentLength = JcrItemResource.getContentLength(data);
}
}
} catch (final RepositoryException re) {
report(re);
}
internalPut(CONTENT_LENGTH, contentLength);
return contentLength;
}
return null;
}
private Item getPrimaryItem(final Node node) throws RepositoryException {
String name = node.getPrimaryNodeType().getPrimaryItemName();
if (name == null) {
return null;
}
if (node.hasProperty(name)) {
return node.getProperty(name);
} else if (node.hasNode(name)) {
return node.getNode(name);
} else {
return null;
}
}
private void populate() {
if (populated) {
return;
}
get(CREATION_TIME);
get(CONTENT_TYPE);
get(CHARACTER_ENCODING);
get(MODIFICATION_TIME);
get(CONTENT_LENGTH);
populated = true;
}
@Override
public Set<Map.Entry<String, Object>> entrySet() {
populate();
return super.entrySet();
}
@Override
public Set<String> keySet() {
populate();
return super.keySet();
}
@Override
public Collection<Object> values() {
populate();
return super.values();
}
@Override
public int size() {
populate();
return super.size();
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean containsKey(final Object key) {
if (super.containsKey(key)) {
return true;
}
if (CREATION_TIME.equals(key) ||
CONTENT_TYPE.equals(key) ||
CHARACTER_ENCODING.equals(key) ||
MODIFICATION_TIME.equals(key) ||
CONTENT_LENGTH.equals(key)) {
return true;
}
return false;
}
@Override
public boolean containsValue(final Object value) {
if (super.containsValue(value)) {
return true;
}
if (!populated) {
populate();
return super.containsValue(value);
}
return false;
}
}