package com.bradmcevoy.http.webdav;
import com.bradmcevoy.http.Response;
import com.bradmcevoy.http.Response.Status;
import com.bradmcevoy.http.XmlWriter;
import com.bradmcevoy.http.values.ValueAndType;
import com.bradmcevoy.http.values.ValueWriters;
import com.bradmcevoy.http.webdav.PropFindResponse.NameAndError;
import org.apache.commons.io.output.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author brad
*/
public class PropFindXmlGenerator {
private static final Logger log = LoggerFactory.getLogger( PropFindXmlGenerator.class );
private final Helper helper;
private final ValueWriters valueWriters;
public PropFindXmlGenerator( ValueWriters valueWriters ) {
helper = new Helper();
this.valueWriters = valueWriters;
}
PropFindXmlGenerator( Helper helper, ValueWriters valueWriters ) {
this.helper = helper;
this.valueWriters = valueWriters;
}
public String generate( List<PropFindResponse> propFindResponses ) {
ByteArrayOutputStream responseOutput = new ByteArrayOutputStream();
Map<String, String> mapOfNamespaces = helper.findNameSpaces( propFindResponses );
ByteArrayOutputStream generatedXml = new ByteArrayOutputStream();
XmlWriter writer = new XmlWriter( generatedXml );
writer.writeXMLHeader();
writer.open(WebDavProtocol.NS_DAV.getPrefix() ,"multistatus" + helper.generateNamespaceDeclarations( mapOfNamespaces ) );
writer.newLine();
helper.appendResponses( writer, propFindResponses, mapOfNamespaces );
writer.close(WebDavProtocol.NS_DAV.getPrefix(),"multistatus" );
writer.flush();
// log.debug( generatedXml.toString() );
helper.write( generatedXml, responseOutput );
try {
return responseOutput.toString( "UTF-8" );
} catch( UnsupportedEncodingException ex ) {
throw new RuntimeException( ex );
}
}
class Helper {
/**
*
* @param propFindResponses
* @return - map where key is the uri, and value is the prefix
*/
Map<String, String> findNameSpaces( List<PropFindResponse> propFindResponses ) {
int i = 1;
Map<String, String> map = new HashMap<String, String>();
// always add webdav namespace
map.put( WebDavProtocol.NS_DAV.getName(), WebDavProtocol.NS_DAV.getPrefix() );
for( PropFindResponse r : propFindResponses ) {
for( QName p : r.getKnownProperties().keySet() ) {
String uri = p.getNamespaceURI();
// if( uri.endsWith( ":" ) ) uri = uri.substring( 0, uri.length() - 1 ); // strip trailing :
if( !map.containsKey( uri ) ) {
map.put( uri, "ns" + i++ );
}
}
}
return map;
}
String generateNamespaceDeclarations( Map<String, String> mapOfNamespaces ) {
String decs = "";
for( String uri : mapOfNamespaces.keySet() ) {
String prefix = mapOfNamespaces.get( uri );
decs += " xmlns:" + prefix + "=\"" + uri + "\"";
}
return decs;
}
void appendResponses( XmlWriter writer, List<PropFindResponse> propFindResponses, Map<String, String> mapOfNamespaces ) {
// log.debug( "appendResponses: " + propFindResponses.size() );
for( PropFindResponse r : propFindResponses ) {
XmlWriter.Element el = writer.begin(WebDavProtocol.NS_DAV.getPrefix(), "response" );
el.open();
writer.writeProperty( WebDavProtocol.NS_DAV.getPrefix(), "href", r.getHref() );
sendKnownProperties( writer, mapOfNamespaces, r.getKnownProperties(), r.getHref() );
if( r.getErrorProperties() != null ) {
for( Status status : r.getErrorProperties().keySet()) {
List<NameAndError> props = r.getErrorProperties().get(status);
sendErrorProperties( status, writer, mapOfNamespaces, props );
}
}
el.close();
}
}
private void sendKnownProperties( XmlWriter writer, Map<String, String> mapOfNamespaces, Map<QName, ValueAndType> properties, String href ) {
sendProperties(Response.Status.SC_OK, writer, mapOfNamespaces, properties, href);
}
private void sendProperties( Response.Status status, XmlWriter writer, Map<String, String> mapOfNamespaces, Map<QName, ValueAndType> properties, String href ) {
if( !properties.isEmpty() ) {
XmlWriter.Element elPropStat = writer.begin(WebDavProtocol.NS_DAV.getPrefix(), "propstat" ).open();
XmlWriter.Element elProp = writer.begin(WebDavProtocol.NS_DAV.getPrefix(), "prop" ).open();
for( QName qname : properties.keySet() ) {
String prefix = mapOfNamespaces.get( qname.getNamespaceURI() );
ValueAndType val = properties.get( qname );
valueWriters.writeValue( writer, qname, prefix, val, href, mapOfNamespaces );
}
elProp.close();
writer.writeProperty( WebDavProtocol.NS_DAV.getPrefix(), "status", status.toString() );
elPropStat.close();
}
}
private void sendErrorProperties( Response.Status status, XmlWriter writer, Map<String, String> mapOfNamespaces, List<NameAndError> properties ) {
// log.debug( "sendUnknownProperties: " + properties.size() );
if( !properties.isEmpty() ) {
XmlWriter.Element elPropStat = writer.begin(WebDavProtocol.NS_DAV.getPrefix(), "propstat" ).open();
XmlWriter.Element elProp = writer.begin(WebDavProtocol.NS_DAV.getPrefix(), "prop" ).open();
for( NameAndError ne : properties ) {
QName qname = ne.getName();
String prefix = mapOfNamespaces.get( qname.getNamespaceURI() );
writer.writeProperty( prefix, qname.getLocalPart() );
}
elProp.close();
writer.writeProperty( WebDavProtocol.NS_DAV.getPrefix(), "status", status.toString() );
elPropStat.close();
}
}
void write( ByteArrayOutputStream out, OutputStream outputStream ) {
try {
String xml = out.toString( "UTF-8" );
outputStream.write( xml.getBytes() ); // note: this can and should write to the outputstream directory. but if it aint broke, dont fix it...
} catch( UnsupportedEncodingException ex ) {
throw new RuntimeException( ex );
} catch( IOException ex ) {
throw new RuntimeException( ex );
}
}
}
}