// Copyright (c) 2006-2008 by Leif Frenzel - see http://leiffrenzel.de
// This code is made available under the terms of the Eclipse Public License,
// version 1.0 (EPL). See http://www.eclipse.org/legal/epl-v10.html
package net.sf.eclipsefp.haskell.core.compiler;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import net.sf.eclipsefp.haskell.core.HaskellCorePlugin;
import org.eclipse.core.runtime.IStatus;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/** <p>helper for serializing and de-serializing Haskell implementation
* descriptors.</p>
*
* @author Leif Frenzel
*
*/
public class HsImplementationPersister {
private static final String PREAMBLE
= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; //$NON-NLS-1$
private static final String ELEM_TOP_LEVEL = "hsImpls"; //$NON-NLS-1$
private static final String ELEM_HS_IMPL = "hsImpl"; //$NON-NLS-1$
private static final String ATT_NAME = "name"; //$NON-NLS-1$
private static final String ATT_BIN_DIR = "binDir"; //$NON-NLS-1$
private static final String ATT_VERSION = "version"; //$NON-NLS-1$
private static final String ATT_TYPE = "type"; //$NON-NLS-1$
public static String toXML( final List<IHsImplementation> impls ) {
StringBuilder sb = new StringBuilder( PREAMBLE );
sb.append( "<" ); //$NON-NLS-1$
sb.append( ELEM_TOP_LEVEL );
sb.append( ">\n" ); //$NON-NLS-1$
for( IHsImplementation impl: impls ) {
toXML( impl, sb );
}
sb.append( "</" ); //$NON-NLS-1$
sb.append( ELEM_TOP_LEVEL );
sb.append( ">\n" ); //$NON-NLS-1$
return sb.toString();
}
public static void fromXML( final String xml, final List<IHsImplementation> impls ) {
if( !isEmpty( xml ) ) {
try {
DocumentBuilder parser = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
InputStream is = new ByteArrayInputStream( xml.getBytes() );
Element rootElement = parser.parse( is ).getDocumentElement();
if( rootElement != null ) {
load( rootElement, impls );
}
} catch( final Exception ex ) {
HaskellCorePlugin.log( "Parsing Haskell Implementations", ex ); //$NON-NLS-1$
}
}
}
// helping functions
////////////////////
private static void toXML( final IHsImplementation impl,
final StringBuilder sb ) {
sb.append( " <" ); //$NON-NLS-1$
sb.append( ELEM_HS_IMPL );
appendAtt( ATT_NAME, impl.getName(), sb );
appendAtt( ATT_BIN_DIR, impl.getBinDir(), sb );
appendAtt( ATT_VERSION, impl.getVersion(), sb );
appendAtt( ATT_TYPE, impl.getType().name(), sb );
sb.append( "/>\n" ); //$NON-NLS-1$
}
private static void appendAtt( final String att,
final String value,
final StringBuilder sb ) {
sb.append( " " ); //$NON-NLS-1$
sb.append( att );
sb.append( "=\"" ); //$NON-NLS-1$
sb.append( value );
sb.append( "\"" ); //$NON-NLS-1$
}
private static void load( final Element rootElement,
final List<IHsImplementation> impls) {
NodeList list = rootElement.getElementsByTagName( ELEM_HS_IMPL );
for( int i = 0; i < list.getLength(); i++ ) {
Node item = list.item( i );
NamedNodeMap attributes = item.getAttributes();
if( attributes != null ) {
String name = loadAtt( attributes, ATT_NAME );
String binDir = loadAtt( attributes, ATT_BIN_DIR );
String version = loadAtt( attributes, ATT_VERSION );
String sType = loadAtt( attributes, ATT_TYPE );
if( !isEmpty( name )
&& !isEmpty( binDir )
&& !isEmpty( version )
&& !isEmpty( sType ) ) {
HsImplementationType type = HsImplementationType.valueOf( sType );
HsImplementation hsi = new HsImplementation();
hsi.setType( type );
hsi.setName( name );
hsi.setBinDir( binDir );
hsi.setVersion( version );
IStatus[] status = hsi.validate();
for( IStatus st: status ) {
if( st.matches( IStatus.ERROR ) ) {
HaskellCorePlugin.getDefault().getLog().log( st );
}
}
impls.add( hsi );
}
}
}
}
private static String loadAtt( final NamedNodeMap attributes,
final String attName ) {
String result = null;
Node pathNode = attributes.getNamedItem( attName );
if( pathNode != null ) {
result = pathNode.getNodeValue();
}
return result;
}
private static boolean isEmpty( final String candidate ) {
return candidate == null || candidate.trim().length() == 0;
}
}