package com.bradmcevoy.http.webdav; import com.bradmcevoy.http.Resource; import com.bradmcevoy.http.Response; import com.bradmcevoy.http.Response.Status; import com.bradmcevoy.http.exceptions.NotAuthorizedException; import com.bradmcevoy.http.values.ValueAndType; import com.bradmcevoy.http.values.ValueWriters; import com.bradmcevoy.http.webdav.PropFindResponse.NameAndError; import com.bradmcevoy.http.webdav.PropPatchRequestParser.ParseResult; import com.bradmcevoy.property.PropertySource; import com.bradmcevoy.property.PropertySource.PropertyMetaData; import com.bradmcevoy.property.PropertySource.PropertySetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.xml.namespace.QName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author brad */ public class PropertySourcePatchSetter implements PropPatchSetter { private static final Logger log = LoggerFactory.getLogger( PropertySourcePatchSetter.class ); private final List<PropertySource> propertySources; private final ValueWriters valueWriters; public PropertySourcePatchSetter( List<PropertySource> propertySources, ValueWriters valueWriters ) { this.propertySources = propertySources; this.valueWriters = valueWriters; } public PropertySourcePatchSetter( List<PropertySource> propertySources ) { this.propertySources = propertySources; this.valueWriters = new ValueWriters(); } /** * This returns true for all resources, but it actually depends on the * configured property sources. * * If no property sources support a given resource, a proppatch attempt * will return 404's for all properties * * @param r * @return */ public boolean supports( Resource r ) { return true; } public PropFindResponse setProperties( String href, ParseResult parseResult, Resource r ) { Map<QName, ValueAndType> knownProps = new HashMap<QName, ValueAndType>(); Map<Status, List<NameAndError>> errorProps = new HashMap<Status, List<NameAndError>>(); for( Entry<QName, String> entry : parseResult.getFieldsToSet().entrySet() ) { QName name = entry.getKey(); boolean found = false; for( PropertySource source : propertySources ) { PropertyMetaData meta = source.getPropertyMetaData( entry.getKey(), r ); if( meta != null && !meta.isUnknown() ) { found = true; if( meta.isWritable() ) { Object val = parse( name, entry.getValue(), meta.getValueType() ); try { source.setProperty( name, val, r ); knownProps.put( name, new ValueAndType( null, meta.getValueType() ) ); break; } catch(NotAuthorizedException e) { addErrorProp( errorProps, Response.Status.SC_UNAUTHORIZED, name, "Not authorised" ); break; } catch( PropertySetException ex ) { addErrorProp( errorProps, ex.getStatus(), name, ex.getErrorNotes() ); break; } } else { log.debug( "property is not writable in source: " + source.getClass() ); addErrorProp( errorProps, Response.Status.SC_FORBIDDEN, name, "Property is read only" ); break; } } else { //log.debug( "not found in: " + source.getClass().getCanonicalName() ); } } if( !found ) { log.debug( "property not found: " + entry.getKey() ); addErrorProp( errorProps, Status.SC_NOT_FOUND, entry.getKey(), "Unknown property" ); } } log.debug( "errorProps: " + errorProps.size() ); PropFindResponse resp = new PropFindResponse( href, knownProps, errorProps ); return resp; } private void addErrorProp( Map<Status, List<NameAndError>> errorProps, Status stat, QName name, String err ) { List<NameAndError> list = errorProps.get( stat ); if( list == null ) { list = new ArrayList<NameAndError>(); errorProps.put( stat, list ); } NameAndError ne = new NameAndError( name, err ); list.add( ne ); } private Object parse( QName key, String value, Class valueType ) { return valueWriters.parse( key, valueType, value ); } }