Index: spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/BinaryPartSource.java =================================================================== --- spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/BinaryPartSource.java (revision 0) +++ spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/BinaryPartSource.java (revision 0) @@ -0,0 +1,58 @@ +/* + * 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.jackrabbit.spi2dav; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.commons.httpclient.methods.multipart.PartSource; +import org.apache.jackrabbit.spi.QValue; + +import javax.jcr.RepositoryException; +import java.io.InputStream; +import java.io.IOException; + +/** + * BinaryPartSource... + */ +public class BinaryPartSource implements PartSource { + + private final QValue value; + + BinaryPartSource(QValue value) { + this.value = value; + } + + public long getLength() { + try { + return value.getLength(); + } catch (RepositoryException e) { + throw new IllegalStateException(e.getMessage()); + } + } + + public String getFileName() { + return value.toString(); + } + + public InputStream createInputStream() throws IOException { + try { + return value.getStream(); + } catch (RepositoryException e) { + throw new IOException(e.getMessage()); + } + } +} \ No newline at end of file Property changes on: spi2dav\src\main\java\org\apache\jackrabbit\spi2dav\BinaryPartSource.java ___________________________________________________________________ Name: svn:keywords + author date id revision url Name: svn:eol-style + native Index: spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/ItemInfoImpl.java =================================================================== --- spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/ItemInfoImpl.java (revision 617499) +++ spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/ItemInfoImpl.java (working copy) @@ -47,7 +47,11 @@ DavProperty pathProp = propSet.get(ItemResourceConstants.JCR_PATH); String jcrPath = pathProp.getValue().toString(); path = resolver.getQPath(jcrPath); + } + public ItemInfoImpl(NodeId parentId, Path path) { + this.parentId = parentId; + this.path = path; } public NodeId getParentId() { Index: spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/JcrStringPart.java =================================================================== --- spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/JcrStringPart.java (revision 0) +++ spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/JcrStringPart.java (revision 0) @@ -0,0 +1,74 @@ +/* + * 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.jackrabbit.spi2dav; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.commons.httpclient.methods.multipart.PartBase; +import org.apache.commons.httpclient.methods.multipart.Part; +import org.apache.commons.httpclient.util.EncodingUtil; + +import java.io.OutputStream; +import java.io.IOException; + +/** + * JcrStringPart... + */ +public class JcrStringPart extends PartBase { + + private static Logger log = LoggerFactory.getLogger(JcrStringPart.class); + + /** Default content type */ + public static final String DEFAULT_CONTENT_TYPE = "text/plain"; + + /** Default charset */ + public static final String DEFAULT_CHARSET = "UTF-8"; + + /** Default transfer encoding */ + public static final String DEFAULT_TRANSFER_ENCODING = "8bit"; + + /** Content of this part */ + private final byte[] content; + + /** + * Constructor. + * + * @param name The name of the part + * @param contentType The content type, or null + */ + public JcrStringPart(String name, String value, String contentType) { + super(name, contentType, DEFAULT_CHARSET, DEFAULT_TRANSFER_ENCODING); + if (contentType == null || value == null) { + throw new IllegalArgumentException("Value may not be null"); + } + content = EncodingUtil.getBytes(value, DEFAULT_CHARSET); + } + + /** + * @see Part#sendData(OutputStream) + */ + protected void sendData(OutputStream out) throws IOException { + out.write(content); + } + + /** + * @see Part#lengthOfData() + */ + protected long lengthOfData() throws IOException { + return content.length; + } +} \ No newline at end of file Property changes on: spi2dav\src\main\java\org\apache\jackrabbit\spi2dav\JcrStringPart.java ___________________________________________________________________ Name: svn:keywords + author date id revision url Name: svn:eol-style + native Index: spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/PropertyInfoImpl.java =================================================================== --- spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/PropertyInfoImpl.java (revision 617499) +++ spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/PropertyInfoImpl.java (working copy) @@ -16,26 +16,21 @@ */ package org.apache.jackrabbit.spi2dav; -import org.apache.jackrabbit.spi.commons.conversion.NameException; -import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; import org.apache.jackrabbit.spi.Name; -import org.apache.jackrabbit.spi.NodeId; import org.apache.jackrabbit.spi.PropertyId; import org.apache.jackrabbit.spi.PropertyInfo; import org.apache.jackrabbit.spi.QValue; -import org.apache.jackrabbit.spi.QValueFactory; -import org.apache.jackrabbit.spi.commons.value.ValueFormat; +import org.apache.jackrabbit.spi.Path; +import org.apache.jackrabbit.spi.commons.conversion.NameException; +import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; import org.apache.jackrabbit.webdav.DavException; import org.apache.jackrabbit.webdav.jcr.ItemResourceConstants; -import org.apache.jackrabbit.webdav.jcr.property.ValuesProperty; import org.apache.jackrabbit.webdav.property.DavPropertySet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; -import javax.jcr.Value; -import javax.jcr.ValueFactory; import java.io.IOException; /** @@ -46,55 +41,47 @@ private static Logger log = LoggerFactory.getLogger(PropertyInfoImpl.class); private final PropertyId id; + private final int type; + private final boolean isMultiValued; - private int type; - private boolean isMultiValued; + private ValueLoader loader; private QValue[] values; - public PropertyInfoImpl(PropertyId id, NodeId parentId, DavPropertySet propSet, - NamePathResolver resolver, ValueFactory valueFactory, - QValueFactory qValueFactory) + public PropertyInfoImpl(PropertyId id, DavPropertySet propSet, + NamePathResolver resolver, ValueLoader loader) throws RepositoryException, DavException, IOException, NameException { - super(parentId, propSet, resolver); + super(id.getParentId(), propSet, resolver); + + if (loader == null) { + throw new IllegalArgumentException(); + } // set id this.id = id; + this.loader = loader; // retrieve properties String typeName = propSet.get(ItemResourceConstants.JCR_TYPE).getValue().toString(); type = PropertyType.valueFromName(typeName); - - // values from jcr-server must be converted to qualified values. - if (propSet.contains(ItemResourceConstants.JCR_VALUE)) { - ValuesProperty vp = new ValuesProperty(propSet.get(ItemResourceConstants.JCR_VALUE), type, valueFactory); - Value jcrValue = vp.getJcrValue(type, valueFactory); - if (jcrValue == null) { - // TODO: should never occur. since 'null' single values are not allowed. rather throw? - values = QValue.EMPTY_ARRAY; - } else { - QValue qv; - if (type == PropertyType.BINARY) { - qv = qValueFactory.create(jcrValue.getStream()); - } else { - qv = ValueFormat.getQValue(jcrValue, resolver, qValueFactory); - } - values = new QValue[] {qv}; - } + if (propSet.contains(ItemResourceConstants.JCR_LENGTH)) { + isMultiValued = false; } else { isMultiValued = true; - ValuesProperty vp = new ValuesProperty(propSet.get(ItemResourceConstants.JCR_VALUES), type, valueFactory); - Value[] jcrValues = vp.getJcrValues(type, valueFactory); - values = new QValue[jcrValues.length]; - for (int i = 0; i < jcrValues.length; i++) { - if (type == PropertyType.BINARY) { - values[i] = qValueFactory.create(jcrValues[i].getStream()); - } else { - values[i] = ValueFormat.getQValue(jcrValues[i], resolver, qValueFactory); - } - } } } + public PropertyInfoImpl(PropertyId id, Path path, int type, + boolean isMultiValued, QValue[] values) { + super(id.getParentId(), path); + if (values == null) { + throw new IllegalArgumentException(); + } + this.id = id; + this.type = type; + this.isMultiValued = isMultiValued; + this.values = values; + } + //-----------------------------------------------------------< ItemInfo >--- public boolean denotesNode() { return false; @@ -118,6 +105,14 @@ } public QValue[] getValues() { + if (values == null) { + try { + values = loader.loadValues(type, isMultiValued); + } catch (Exception e) { + log.error("Internal error while loading property value(s).", e); + throw new IllegalStateException("Unable to load property values."); + } + } return values; } } Index: spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/QPropertyDefinitionImpl.java =================================================================== --- spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/QPropertyDefinitionImpl.java (revision 617499) +++ spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/QPropertyDefinitionImpl.java (working copy) @@ -26,6 +26,8 @@ import org.apache.jackrabbit.webdav.xml.DomUtil; import org.apache.jackrabbit.webdav.xml.ElementIterator; import org.w3c.dom.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; @@ -40,6 +42,8 @@ */ public class QPropertyDefinitionImpl extends QItemDefinitionImpl implements QPropertyDefinition { + private static Logger log = LoggerFactory.getLogger(QPropertyDefinitionImpl.class); + /** * The required type. */ @@ -91,6 +95,10 @@ ElementIterator it = DomUtil.getChildren(child, DEFAULTVALUE_ELEMENT, null); while (it.hasNext()) { String jcrVal = DomUtil.getText(it.nextElement()); + if (jcrVal == null) { + log.debug("PropertyDefinition: defaultValue is null -> ignoring"); + continue; + } QValue qValue; if (requiredType == PropertyType.BINARY) { // TODO: improve @@ -101,7 +109,7 @@ } vs.add(qValue); } - defaultValues = (QValue[]) vs.toArray(new QValue[vs.size()]); + defaultValues = (vs.isEmpty()) ? null : (QValue[]) vs.toArray(new QValue[vs.size()]); } child = DomUtil.getChildElement(pdefElement, VALUECONSTRAINTS_ELEMENT, null); Index: spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java =================================================================== --- spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java (revision 617499) +++ spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java (working copy) @@ -26,7 +26,13 @@ import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.HeadMethod; import org.apache.commons.httpclient.methods.InputStreamRequestEntity; +import org.apache.commons.httpclient.methods.RequestEntity; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.apache.commons.httpclient.methods.multipart.Part; +import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; +import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; +import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException; import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException; import org.apache.jackrabbit.spi.commons.conversion.NameException; @@ -173,6 +179,7 @@ import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -832,7 +839,12 @@ // currently: missing 'value/values' property PropertyInfo cannot be built // currently: missing prop-names with child-NodeInfo List l = new ArrayList(); - l.add(getNodeInfo(sessionInfo, nodeId)); + NodeInfo nInfo = getNodeInfo(sessionInfo, nodeId); + l.add(nInfo); + // at least add propertyInfos for the meta-props already known from the + // nodeInfo. + l.addAll(buildPropertyInfos(nInfo)); + return l.iterator(); } @@ -854,6 +866,41 @@ return nInfo; } + private List buildPropertyInfos(NodeInfo nInfo) throws RepositoryException { + List l = new ArrayList(3); + NodeId nid = nInfo.getId(); + Path nPath = nInfo.getPath(); + + if (nid.getPath() == null) { + PropertyId id = getIdFactory().createPropertyId(nid, NameConstants.JCR_UUID); + QValue[] vs = new QValue[] {getQValueFactory().create(nid.getUniqueID(), PropertyType.STRING)}; + Path p = getPathFactory().create(nPath, NameConstants.JCR_UUID, true); + PropertyInfo pi = new PropertyInfoImpl(id, p, PropertyType.STRING, false, vs); + l.add(pi); + } + + Name pName = NameConstants.JCR_PRIMARYTYPE; + QValue[] vs = new QValue[] {getQValueFactory().create(nInfo.getNodetype())}; + PropertyInfo pi = new PropertyInfoImpl(getIdFactory().createPropertyId(nid, pName), + getPathFactory().create(nPath, pName, true), PropertyType.NAME, false, vs); + l.add(pi); + + Name[] mixins = nInfo.getMixins(); + if (mixins.length > 0) { + pName = NameConstants.JCR_MIXINTYPES; + vs = new QValue[mixins.length]; + for (int i = 0; i < mixins.length; i++) { + vs[i] = getQValueFactory().create(mixins[i]); + } + pi = new PropertyInfoImpl(getIdFactory().createPropertyId(nid, pName), + getPathFactory().create(nPath, pName, true), PropertyType.NAME, + true, vs); + l.add(pi); + } + + return l; + } + /** * @see RepositoryService#getChildInfos(SessionInfo, NodeId) */ @@ -923,8 +970,8 @@ nameSet.add(ItemResourceConstants.JCR_NAME); nameSet.add(ItemResourceConstants.JCR_PARENT); nameSet.add(ItemResourceConstants.JCR_TYPE); - nameSet.add(ItemResourceConstants.JCR_VALUE); - nameSet.add(ItemResourceConstants.JCR_VALUES); + nameSet.add(ItemResourceConstants.JCR_LENGTH); + nameSet.add(ItemResourceConstants.JCR_LENGTHS); nameSet.add(ItemResourceConstants.JCR_PATH); nameSet.add(DavPropertyName.RESOURCETYPE); @@ -932,7 +979,8 @@ try { String uri = getItemUri(propertyId, sessionInfo); method = new PropFindMethod(uri, nameSet, DEPTH_0); - getClient(sessionInfo).executeMethod(method); + HttpClient client = getClient(sessionInfo); + client.executeMethod(method); method.checkSuccess(); MultiStatusResponse[] responses = method.getResponseBodyAsMultiStatus().getResponses(); @@ -945,8 +993,8 @@ PropertyId id = uriResolver.buildPropertyId(parentId, responses[0], sessionInfo.getWorkspaceName(), getNamePathResolver(sessionInfo)); NamePathResolver resolver = getNamePathResolver(sessionInfo); - PropertyInfo pInfo = new PropertyInfoImpl(id, parentId, propSet, - resolver, valueFactory, getQValueFactory()); + PropertyInfo pInfo = new PropertyInfoImpl(id, propSet, resolver, + new ValueLoader(uri, client, getQValueFactory(), resolver)); return pInfo; } catch (IOException e) { throw new RepositoryException(e); @@ -1896,7 +1944,7 @@ private BatchImpl(ItemId targetId, SessionInfo sessionInfo) throws RepositoryException { this.targetId = targetId; this.sessionInfo = sessionInfo; - this.resolver = getNamePathResolver(sessionInfo); + resolver = getNamePathResolver(sessionInfo); } private HttpClient start() throws RepositoryException { @@ -2023,9 +2071,12 @@ */ public void addProperty(NodeId parentId, Name propertyName, QValue value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, PathNotFoundException, ItemExistsException, AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { checkConsumed(); - Value jcrValue = ValueFormat.getJCRValue(value, resolver, valueFactory); - ValuesProperty vp = new ValuesProperty(jcrValue); - internalAddProperty(parentId, propertyName, vp); + String uri = getItemUri(parentId, propertyName, sessionInfo); + + PutMethod method = new PutMethod(uri); + method.setRequestHeader(DavConstants.HEADER_CONTENT_TYPE, getContentType(value.getType())); + method.setRequestEntity(getEntity(value)); + methods.add(method); } /** @@ -2033,22 +2084,19 @@ */ public void addProperty(NodeId parentId, Name propertyName, QValue[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, PathNotFoundException, ItemExistsException, AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { checkConsumed(); - Value[] jcrValues = new Value[values.length]; - for (int i = 0; i < values.length; i++) { - jcrValues[i] = ValueFormat.getJCRValue(values[i], resolver, valueFactory); - } - ValuesProperty vp = new ValuesProperty(jcrValues); - internalAddProperty(parentId, propertyName, vp); - } - - private void internalAddProperty(NodeId parentId, Name propertyName, ValuesProperty vp) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, PathNotFoundException, ItemExistsException, AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { + // TODO: avoid usage of the ValuesProperty. specially for binary props. + // TODO: replace by a multipart-POST try { String uri = getItemUri(parentId, propertyName, sessionInfo); + Value[] jcrValues = new Value[values.length]; + for (int i = 0; i < values.length; i++) { + jcrValues[i] = ValueFormat.getJCRValue(values[i], resolver, valueFactory); + } + ValuesProperty vp = new ValuesProperty(jcrValues); PutMethod method = new PutMethod(uri); method.setRequestBody(vp); methods.add(method); - } catch (IOException e) { throw new RepositoryException(e); } @@ -2059,17 +2107,19 @@ */ public void setValue(PropertyId propertyId, QValue value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { checkConsumed(); - DavPropertySet setProperties = new DavPropertySet(); if (value == null) { // setting property value to 'null' is identical to a removal remove(propertyId); } else { - // qualified value must be converted to jcr value - Value jcrValue = ValueFormat.getJCRValue(value, resolver, valueFactory); - ValuesProperty vp = new ValuesProperty(jcrValue); - setProperties.add(vp); + RequestEntity ent = getEntity(value); + String uri = getItemUri(propertyId, sessionInfo); + // TODO: use PUT in order to avoid the ValuesProperty-PROPPATCH call. + // TODO: actually not quite correct for PROPPATCH assert that prop really exists. + PutMethod method = new PutMethod(uri); + method.setRequestHeader(DavConstants.HEADER_CONTENT_TYPE, getContentType(value.getType())); + method.setRequestEntity(ent); + methods.add(method); } - internalSetValue(propertyId, setProperties); } /** @@ -2077,44 +2127,98 @@ */ public void setValue(PropertyId propertyId, QValue[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { checkConsumed(); - DavPropertySet setProperties = new DavPropertySet(); if (values == null) { // setting property value to 'null' is identical to a removal remove(propertyId); } else { + // TODO: use multipart-POST instead of ValuesProperty + DavPropertySet setProperties = new DavPropertySet(); // qualified values must be converted to jcr values Value[] jcrValues = new Value[values.length]; for (int i = 0; i < values.length; i++) { jcrValues[i] = ValueFormat.getJCRValue(values[i], resolver, valueFactory); } setProperties.add(new ValuesProperty(jcrValues)); + try { + String uri = getItemUri(propertyId, sessionInfo); + PropPatchMethod method = new PropPatchMethod(uri, setProperties, new DavPropertyNameSet()); + methods.add(method); + } catch (IOException e) { + throw new RepositoryException(e); + } } - internalSetValue(propertyId, setProperties); } + private RequestEntity getEntity(QValue value) throws RepositoryException { + // qualified value must be converted to jcr value + InputStream in; + int type = value.getType(); + String contentType = getContentType(type); + RequestEntity ent; + try { + switch (type) { + case PropertyType.NAME: + case PropertyType.PATH: + Value v = ValueFormat.getJCRValue(value, resolver, valueFactory); + ent = new StringRequestEntity(v.getString(), contentType, "UTF-8"); + break; + case PropertyType.BINARY: + in = value.getStream(); + ent = new InputStreamRequestEntity(in, contentType); + break; + default: + String str = value.getString(); + ent = new StringRequestEntity(str, contentType, "UTF-8"); + break; + } + } catch (UnsupportedEncodingException e) { + // should never get here + throw new RepositoryException(e.getMessage()); + } + return ent; + } + /** + * Create a multipart request entity that would be used by {@link #addProperty} + * and {@link #setValue} taking an array of QValue objects. + * Currently this method is not used, since the jcr-server is not able + * to deal with multipart-post requests. (TODO: TOBEFIXED) * - * @param propertyId - * @param setProperties - * @throws ValueFormatException - * @throws VersionException - * @throws LockException - * @throws ConstraintViolationException - * @throws AccessDeniedException - * @throws UnsupportedRepositoryOperationException + * @param values + * @param params + * @return * @throws RepositoryException */ - private void internalSetValue(PropertyId propertyId, DavPropertySet setProperties) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { - try { - String uri = getItemUri(propertyId, sessionInfo); - PropPatchMethod method = new PropPatchMethod(uri, setProperties, new DavPropertyNameSet()); - - methods.add(method); - } catch (IOException e) { - throw new RepositoryException(e); + private RequestEntity getEntity(QValue[] values, HttpMethodParams params) throws RepositoryException { + // qualified value must be converted to jcr value + Part[] parts = new Part[values.length]; + for (int i = 0; i < values.length; i++) { + int type = values[i].getType(); + String partname = i + "_" + PropertyType.nameFromValue(type); + String contentType = getContentType(type); + switch (type) { + case PropertyType.NAME: + case PropertyType.PATH: + Value v = ValueFormat.getJCRValue(values[i], resolver, valueFactory); + parts[i] = new JcrStringPart(partname, v.getString(), contentType); + break; + case PropertyType.BINARY: + parts[i] = new FilePart(partname, new BinaryPartSource(values[i])); + break; + default: + String str = values[i].getString(); + parts[i] = new JcrStringPart(partname, str, contentType); + break; + } } + RequestEntity ent = new MultipartRequestEntity(parts, params); + return ent; } + private String getContentType(int type) { + return ItemResourceConstants.VALUE_CONTENT_TYPE_FRAGMENT + PropertyType.nameFromValue(type).toLowerCase(); + } + /** * @see Batch#remove(ItemId) */ Index: spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/ValueLoader.java =================================================================== --- spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/ValueLoader.java (revision 0) +++ spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/ValueLoader.java (revision 0) @@ -0,0 +1,157 @@ +/* + * 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.jackrabbit.spi2dav; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.jackrabbit.spi.Name; +import org.apache.jackrabbit.spi.Path; +import org.apache.jackrabbit.spi.QValue; +import org.apache.jackrabbit.spi.QValueFactory; +import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; +import org.apache.jackrabbit.spi.commons.value.QValueValue; +import org.apache.jackrabbit.spi.commons.value.ValueFactoryQImpl; +import org.apache.jackrabbit.webdav.DavServletResponse; +import org.apache.jackrabbit.webdav.jcr.ItemResourceConstants; +import org.apache.jackrabbit.webdav.jcr.property.ValuesProperty; +import org.apache.jackrabbit.webdav.property.DavProperty; +import org.apache.jackrabbit.webdav.property.DefaultDavProperty; +import org.apache.jackrabbit.webdav.xml.DomUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.xml.parsers.DocumentBuilder; +import java.io.IOException; +import java.io.InputStream; + +/** + * ValueLoader... + */ +class ValueLoader { + + private static Logger log = LoggerFactory.getLogger(ValueLoader.class); + + private final String uri; + private final HttpClient client; + private final QValueFactory factory; + private final ValueFactoryQImpl vf; + private final NamePathResolver resolver; + + ValueLoader(String uri, HttpClient client, QValueFactory factory, NamePathResolver resolver) { + this.uri = uri; + this.client = client; + this.factory = factory; + this.resolver = resolver; + + vf = new ValueFactoryQImpl(factory, resolver); + } + + QValue[] loadValues(int type, boolean isMultiValued) throws IOException, RepositoryException { + if (type == PropertyType.BINARY) { + return loadBinary(uri, isMultiValued); + } else { + return loadString(uri, type, isMultiValued); + } + } + + private QValue[] loadBinary(String uri, boolean isMultiValued) throws RepositoryException, IOException { + GetMethod method = new GetMethod(uri); + try { + int statusCode = client.executeMethod(method); + if (statusCode == DavServletResponse.SC_OK) { + if (isMultiValued) { + return getValues(method.getResponseBodyAsStream(), PropertyType.BINARY); + } else { + QValue v = factory.create(method.getResponseBodyAsStream()); + return new QValue[] {v}; + } + } else { + throw new RepositoryException("Unable to load binary. Status = " + statusCode); + } + } catch (HttpException e) { + throw new RepositoryException(e); + } finally { + method.releaseConnection(); + } + } + + private QValue[] loadString(String uri, int type, boolean isMultiValued) throws RepositoryException, IOException { + GetMethod method = new GetMethod(uri); + try { + int statusCode = client.executeMethod(method); + if (statusCode == DavServletResponse.SC_OK) { + if (isMultiValued) { + return getValues(method.getResponseBodyAsStream(), type); + } else { + String str = method.getResponseBodyAsString(); + QValue v; + // name/path values from jcr-server must be converted to + // qualified values. + if (type == PropertyType.NAME) { + Name n = resolver.getQName(str); + v = factory.create(n); + } else if (type == PropertyType.PATH) { + Path p = resolver.getQPath(str); + v = factory.create(p); + } else { + v = factory.create(str, type); + } + return new QValue[] {v}; + } + } else { + throw new RepositoryException("Unable to load binary. Status = " + statusCode); + } + } catch (HttpException e) { + throw new RepositoryException(e); + } finally { + method.releaseConnection(); + } + } + + private QValue[] getValues(InputStream response, int type) throws RepositoryException { + try { + DocumentBuilder db = DomUtil.BUILDER_FACTORY.newDocumentBuilder(); + Document doc = db.parse(response); + Element prop = DomUtil.getChildElement(doc, ItemResourceConstants.JCR_VALUES.getName(), ItemResourceConstants.JCR_VALUES.getNamespace()); + DavProperty p = DefaultDavProperty.createFromXml(prop); + ValuesProperty vp = new ValuesProperty(p, type, vf); + + Value[] jcrVs = vp.getJcrValues(type, vf); + QValue[] qvs = new QValue[jcrVs.length]; + + for (int i = 0; i < jcrVs.length; i++) { + if (jcrVs[i] instanceof QValueValue) { + qvs[i] = ((QValueValue) jcrVs[i]).getQValue(); + } else if (type == PropertyType.BINARY) { + qvs[i] = factory.create(jcrVs[i].getStream()); + } else { + qvs[i] = factory.create(jcrVs[i].getString(), type); + } + } + return qvs; + } catch (Exception e) { + log.error("Internal Error: ", e); + throw new RepositoryException(e); + } + } +} \ No newline at end of file Property changes on: spi2dav\src\main\java\org\apache\jackrabbit\spi2dav\ValueLoader.java ___________________________________________________________________ Name: svn:keywords + author date id revision url Name: svn:eol-style + native