Index: build.xml
===================================================================
--- build.xml	(revision 7490)
+++ build.xml	(revision 7491)
@@ -101,7 +101,14 @@
 	<target name="init" depends="config">
 		<path id="compile.classpath">
 			<pathelement location="${jsdk}" />
-			<pathelement location="lib" />
+            <fileset dir='lib/lucene'>
+                <include name='*.jar'/>
+            </fileset>
+            <fileset dir='lib/solr'>
+                <include name='*.jar'/>
+            </fileset>
+
+            <pathelement location="lib" />
 			<fileset dir="lib">
 				<include name="*.jar" />
 			</fileset>
Index: lib/spring-fake.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/spring-fake.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: lib/lucene/lucene-queries-4.1.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/lucene/lucene-queries-4.1.0.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: lib/lucene/lucene-spatial-4.1.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/lucene/lucene-spatial-4.1.0.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: lib/lucene/lucene-analyzers-common-4.1.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/lucene/lucene-analyzers-common-4.1.0.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: lib/lucene/lucene-queryparser-4.1.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/lucene/lucene-queryparser-4.1.0.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: lib/lucene/lucene-facet-4.1.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/lucene/lucene-facet-4.1.0.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: lib/lucene/lucene-core-4.1.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/lucene/lucene-core-4.1.0.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: lib/solr/solr-solrj-4.1.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/solr/solr-solrj-4.1.0.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: lib/solr/solr-core-4.1.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/solr/solr-core-4.1.0.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: lib/d1_cn_index_processor.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/d1_cn_index_processor.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: lib/style/common/eml_xsl.css
===================================================================
--- lib/style/common/eml_xsl.css	(revision 7490)
+++ lib/style/common/eml_xsl.css	(revision 7491)
@@ -1192,3 +1192,35 @@
     font-style:                 normal;
     font-weight:                700;
 }
+
+/**
+* For EML spec styling
+**/
+div.book {
+	margin: 20px;	
+}
+
+div.book a:link {
+	text-decoration: underline;		
+}
+
+div.title {
+    color:                      #003366;
+    background-color:           #ffffff;
+    padding:                    0;
+    font-size:                  16pt;
+    font-style:                 normal;
+    font-weight:                bold;
+    text-decoration:            none;
+}
+
+div.sectiontitle {
+    color:                      #003366;
+    background-color:           #ffffff;
+    padding:                    0;
+    font-size:                  14pt;
+    font-style:                 normal;
+    font-weight:                700;
+    text-decoration:            none;
+}
+
Index: src/edu/ucsb/nceas/metacat/index/D1IndexField.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/D1IndexField.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/D1IndexField.java	(revision 7491)
@@ -0,0 +1,95 @@
+package edu.ucsb.nceas.metacat.index;
+import org.dataone.cn.indexer.convert.*;
+import org.dataone.cn.indexer.parser.SolrField;
+import org.dataone.cn.indexer.solrhttp.SolrElementField;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.List;
+
+/*
+ * Wrapper to use DataONE indexer's field-processing code for extraction.
+ *
+*/
+
+public class D1IndexField extends FieldSpec {
+	// man Java enums are awful
+	public enum DataFormat { SINGLE, SET, MULTISET }
+	public enum Conversion { NONE, DATE, FGDCDATE, LATITUDE, LONGITUDE, FORMAT }
+
+	private static DocumentBuilder docBuilder = null;
+	private static final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+	private static final XPath xpath = XPathFactory.newInstance().newXPath();
+	static {
+		dbf.setNamespaceAware(true);
+
+		try {
+			docBuilder = dbf.newDocumentBuilder();
+		} catch (ParserConfigurationException e) {
+			e.printStackTrace();
+		}
+		xpath.setNamespaceContext(new MCXmlNamespace());
+	}
+
+	private SolrField d1SolrField;
+
+	public D1IndexField(String name, String xp, DataFormat d, Conversion c) {
+		super(name);
+
+		IConverter conv = null;
+		switch (c) {
+			case NONE: conv = null; break;
+			case DATE: conv = new SolrDateConverter(); break;
+			case FGDCDATE: conv = new FgdcDateConverter(); break;
+			case LATITUDE: conv = new SolrLatitudeConverter(); break;
+			case LONGITUDE: conv = new SolrLongitudeConverter(); break;
+			case FORMAT: conv = new FormatIdToFormatTypeConverter(); break;
+		}
+		this.d1SolrField = new SolrField(name, xp, d != DataFormat.SINGLE, conv);
+		if (d == DataFormat.SINGLE) {
+			this.d1SolrField.setCombineNodes(true);
+		}
+		else if (d == DataFormat.SET) {
+			this.d1SolrField.setDedupe(true);
+		}
+
+		this.d1SolrField.initExpression(D1IndexField.xpath);
+	}
+
+	@Override
+	public String[] extract(final Reader in) {
+		List<SolrElementField> fieldList = null;
+		try {
+			// TODO: encodings
+			Document doc = docBuilder.parse(new InputSource(in));
+			fieldList = this.solrFields(doc);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		if (fieldList != null) {
+			String[] fields = new String[fieldList.size()];
+			int i = 0;
+			for (SolrElementField f : fieldList) {
+				fields[i++] = f.getValue();
+			}
+			return fields;
+		} else {
+			return new String[0];
+		}
+	}
+
+	// convenience method for use with DataONE SolrDoc
+	public List<SolrElementField> solrFields(final Document doc)
+			throws XPathExpressionException, IOException, ParserConfigurationException, SAXException {
+		return this.d1SolrField.processField(doc);
+	}
+}
Index: src/edu/ucsb/nceas/metacat/index/XpathIndexField.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/XpathIndexField.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/XpathIndexField.java	(revision 7491)
@@ -0,0 +1,39 @@
+package edu.ucsb.nceas.metacat.index;
+
+import java.io.Reader;
+
+import edu.ucsb.nceas.metacat.index.D1IndexField.DataFormat;
+import edu.ucsb.nceas.metacat.index.D1IndexField.Conversion;
+
+/*
+ * Simple xpath-based indexing. Accepts DOM-parseable data, extracts text data from all
+ * nodes selected by an XPath expression concatenated into a single Lucene/SOLR field
+ * body. Equivalent to the DataONE indexer's MergeSolrField bean.
+ *
+ * Currently just wraps DataONE SolrField code.
+ */
+
+public class XpathIndexField extends FieldSpec {
+	private static final String separator = " ";
+	private static final String textSelector = "text()";
+	public final String xpath;
+
+	public XpathIndexField(String name, String xp) {
+		super(name);
+		this.xpath = xp;
+	}
+
+	@Override
+	public String[] extract(Reader in) {
+		String s = this.xpath;
+		if (!this.xpath.endsWith(textSelector)) {
+			if (this.xpath.charAt(this.xpath.length()-1) != '/') {
+				s = s + "/";
+			}
+			s = s + textSelector;
+		}
+
+		D1IndexField field = new D1IndexField(this.name, s, DataFormat.SINGLE, Conversion.NONE);
+		return field.extract(in);
+	}
+}
Index: src/edu/ucsb/nceas/metacat/index/SolrjIndex.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/SolrjIndex.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/SolrjIndex.java	(revision 7491)
@@ -0,0 +1,67 @@
+package edu.ucsb.nceas.metacat.index;
+
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.HttpSolrServer;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.SolrInputDocument;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class SolrjIndex implements GenericIndex {
+	protected SolrServer solr = null;
+
+	SolrjIndex(String uri) {
+		this.solr = new HttpSolrServer(uri);
+	}
+
+	public void insert(String docID, Map<String, String[]> fields) throws IOException {
+		this.update(docID, fields);
+	}
+
+	public void update(String docID, Map<String, String[]> fields) throws IOException {
+		SolrInputDocument doc = new SolrInputDocument();
+		doc.addField(MetacatIndex.MCIDFIELD, docID);
+		for (String k : fields.keySet()) {
+			for (String v : fields.get(k)) {
+				doc.addField(k, v);
+			}
+		}
+		try {
+			this.solr.add(doc);
+		} catch (SolrServerException e) {
+			e.printStackTrace();
+		}
+	}
+
+	public void remove(String docID) throws IOException {
+		try {
+			solr.deleteByQuery(MetacatIndex.MCIDFIELD + ":" + docID);
+		} catch (SolrServerException e) {
+			// TODO: handling
+			e.printStackTrace();
+		}
+	}
+
+	public String[] query(String q) {
+		SolrQuery sq = new SolrQuery(q);
+		QueryResponse rsp = null;
+		try {
+			rsp = solr.query(sq);
+		} catch (SolrServerException e) {
+			// TODO: handling
+			e.printStackTrace();
+		}
+		SolrDocumentList docs = rsp.getResults();
+		String[] docIDs = new String[docs.size()];
+		int i = 0;
+		for (SolrDocument d : docs) {
+			docIDs[i++] = d.getFieldValue(MetacatIndex.MCIDFIELD).toString();
+		}
+		return docIDs;
+	}
+}
Index: src/edu/ucsb/nceas/metacat/index/LuceneIndex.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/LuceneIndex.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/LuceneIndex.java	(revision 7491)
@@ -0,0 +1,85 @@
+package edu.ucsb.nceas.metacat.index;
+
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.StringField;
+import org.apache.lucene.document.TextField;
+import org.apache.lucene.index.*;
+import org.apache.lucene.queryparser.classic.ParseException;
+import org.apache.lucene.queryparser.classic.QueryParser;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.lucene.util.Version;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+public class LuceneIndex implements GenericIndex {
+	protected final StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_41);
+	protected final IndexWriterConfig cfg = new IndexWriterConfig(Version.LUCENE_41, analyzer);
+	protected final QueryParser parser = new QueryParser(Version.LUCENE_41, MetacatIndex.MCIDFIELD, analyzer);
+	protected IndexWriter writer = null;
+	protected DirectoryReader reader = null;
+	protected Directory index = null;
+
+	public LuceneIndex(File fsIndex) {
+		try {
+			this.index = FSDirectory.open(fsIndex);
+			this.cfg.setOpenMode(IndexWriterConfig.OpenMode.APPEND);
+			this.writer = new IndexWriter(this.index, this.cfg);
+			this.reader = DirectoryReader.open(this.index);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	public void insert(String docID, Map<String, String[]> fields) throws IOException {
+		this.update(docID, fields);
+	}
+
+	public void update(String docID, Map<String, String[]> fields) throws IOException {
+		Document d = new Document();
+		d.add(new StringField(MetacatIndex.MCIDFIELD, docID, Field.Store.YES));
+		for (String k : fields.keySet()) {
+			for (String v : fields.get(k)) {
+				d.add(new TextField(k, v, Field.Store.NO));
+			}
+		}
+		this.writer.addDocument(d);
+		this.writer.commit();
+	}
+
+	public void remove(String docID) throws IOException {
+		this.writer.deleteDocuments(new Term(MetacatIndex.MCIDFIELD, docID));
+		this.writer.commit();
+	}
+
+	public String[] query(String q) {
+		try {
+			DirectoryReader newReader = DirectoryReader.openIfChanged(this.reader);
+			if (newReader != null) { // not sure if this is right...
+				this.reader.close();
+				this.reader = newReader;
+			}
+			IndexSearcher searcher = new IndexSearcher(this.reader);
+			TopDocs docs = searcher.search(this.parser.parse(q), 100);
+			String docIDs[] = new String[docs.scoreDocs.length];
+			int i = 0;
+			for (ScoreDoc sd : docs.scoreDocs) {
+				Document d = searcher.doc(sd.doc);
+				docIDs[i++] = d.getField(MetacatIndex.MCIDFIELD).toString();
+			}
+			return docIDs;
+		} catch (IOException e) {
+			e.printStackTrace();
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		return new String[0];
+	}
+}
\ No newline at end of file
Index: src/edu/ucsb/nceas/metacat/index/GenericIndex.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/GenericIndex.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/GenericIndex.java	(revision 7491)
@@ -0,0 +1,15 @@
+package edu.ucsb.nceas.metacat.index;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * The simplest of index interfaces. Create and remove associations between document
+ * IDs and sets of tagged data; search with arbitrary query language.
+ */
+public interface GenericIndex {
+	public void insert(String docID, final Map<String,String[]> fields) throws IOException;
+	public void update(String docID, final Map<String,String[]> fields) throws IOException;
+	public void remove(String docID) throws IOException;
+	public String[] query(String q);
+}
Index: src/edu/ucsb/nceas/metacat/index/FieldDefReader.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/FieldDefReader.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/FieldDefReader.java	(revision 7491)
@@ -0,0 +1,45 @@
+package edu.ucsb.nceas.metacat.index;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Read field definitions from a file. Replacement for Spring-based config used in DataONE.
+ * Presently uses csv-style text which is primitive and fragile; should probably be some
+ * sort of xml to be properly javaee-esque. It's possible to use Spring configuration info
+ * directly, but the parsing and evaluation involved is non-trivial, even though the data
+ * involved is really quite simple. Thus at present our config info has been manually
+ * generated in this format, based on the DataONE indexer's definitions.
+ *
+ * Oh Java, when will you get a decent object syntax?
+ */
+public class FieldDefReader {
+	public static List<FieldSpec> read(File f) {
+		ArrayList<FieldSpec> specs = new ArrayList<FieldSpec>(20);
+		try {
+			BufferedReader r = new BufferedReader(new FileReader(f));
+			String s;
+			while ((s = r.readLine()) != null) {
+				String[] def = s.split(" ");
+				D1IndexField.DataFormat df = D1IndexField.DataFormat.SINGLE;
+				if (def[2].equals("set")) df = D1IndexField.DataFormat.SET;
+				else if (def[2].equals("multi")) df = D1IndexField.DataFormat.MULTISET;
+				D1IndexField.Conversion dc = D1IndexField.Conversion.NONE;
+				if (def[3].equals("date")) dc = D1IndexField.Conversion.DATE;
+				else if (def[3].equals("fgdc")) dc = D1IndexField.Conversion.FGDCDATE;
+				else if (def[3].equals("lat")) dc = D1IndexField.Conversion.LATITUDE;
+				else if (def[3].equals("lon")) dc = D1IndexField.Conversion.LONGITUDE;
+				specs.add(new D1IndexField(def[0], def[1], df, dc));
+			}
+			r.close();
+		} catch (IOException e) {
+			// TODO: logs
+			e.printStackTrace();
+		}
+		return specs;
+	}
+}
Index: src/edu/ucsb/nceas/metacat/index/HttpComponentsClientHttpRequestFactory.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/HttpComponentsClientHttpRequestFactory.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/HttpComponentsClientHttpRequestFactory.java	(revision 7491)
@@ -0,0 +1,19 @@
+//package edu.ucsb.nceas.metacat.index;
+package org.springframework.http.client;
+
+import org.apache.http.client.HttpClient;
+
+/**
+ * A fake implementation of a Spring framework object for use by the DataONE HttpService class.
+ *
+ */
+
+public class HttpComponentsClientHttpRequestFactory {
+	protected HttpClient client;
+	public HttpComponentsClientHttpRequestFactory(HttpClient c) {
+		this.client = c;
+	}
+	public HttpClient getHttpClient() {
+		return client;
+	}
+}
Index: src/edu/ucsb/nceas/metacat/index/MetacatIndex.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/MetacatIndex.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/MetacatIndex.java	(revision 7491)
@@ -0,0 +1,99 @@
+package edu.ucsb.nceas.metacat.index;
+
+//import edu.ucsb.nceas.metacat.util.SystemUtil;
+
+import java.io.*;
+import java.util.*;
+
+/*
+*
+*/
+
+public class MetacatIndex {
+	// singleton, though it doesn't really need to be -- simplifies configuration a bit
+	private static MetacatIndex instance = null;
+
+	public MetacatIndex getInstance() {
+		if (instance != null) {
+			instance = new MetacatIndex();
+		}
+		return instance;
+		// return new MetacatIndex();
+	}
+
+	public static final String MCIDFIELD = "metacat-id";
+	public static final String MCIndexName = "index";
+	protected GenericIndex index = null;
+	protected String dataPath = null;
+	protected List<FieldSpec> fields;
+	// These are separated to more easily replicate the exact behavior of the DataONE indexer
+	// but probably this is unnecessary and they can simply be agglomerated
+	protected List<FieldSpec> d1SysFields, d1EmlFields, d1DryadFields, d1FgdcFields;
+
+	private MetacatIndex() {
+		this.dataPath = "/Users/brendan/metacat/"; //PropertyService.getProperty("application.datafilepath");
+		this.index = new SolrjIndex("http://localhost:8983"); //PropertyService.getProperty("");
+		this.d1SysFields = FieldDefReader.read(new File(this.dataPath + "d1sys"));
+		this.d1EmlFields = FieldDefReader.read(new File(this.dataPath + "d1eml"));
+		this.d1DryadFields = FieldDefReader.read(new File(this.dataPath + "d1dryad"));
+		this.d1FgdcFields = FieldDefReader.read(new File(this.dataPath + "d1fgdc"));
+		readMCIndexPaths();
+	}
+
+	protected void readMCIndexPaths() {
+		List<String> paths = new ArrayList<String>();//SystemUtil.getPathsforIndexing(); //nullable?
+		for (String p : paths) {
+			this.fields.add(new XpathIndexField("mcidx_" + p, p));
+		}
+	}
+
+	public void update(String docID, Reader doc) {
+		Map<String, String[]> idx = new HashMap<String, String[]>();
+		// this stuff is pretty gross, but it's done to match exactly the behavior of the D1
+		// index processor. Probably isn't necessary and should be replaced by a generalized
+		// dispatch by document/data type.
+		if (DocType.isSysmeta(doc)) {
+			idx.putAll(getFields(this.d1SysFields, doc));
+			if (DocType.isSyseml(doc)) {
+				idx.putAll(getFields(this.d1EmlFields, doc));
+			} else if (DocType.isSysdryad(doc)) {
+				idx.putAll(getFields(this.d1DryadFields, doc));
+			} else if (DocType.isSysfgdc(doc)) {
+				idx.putAll(getFields(this.d1FgdcFields, doc));
+			}
+		} else {
+			if (DocType.isEml(doc)) {
+				idx.putAll(getFields(this.d1EmlFields, doc));
+			}
+			idx.putAll(getFields(this.fields, doc));
+		}
+		try {
+			index.update(docID, idx);
+		} catch (IOException e) {
+			// TODO: logs etc
+			e.printStackTrace();
+		}
+	}
+
+	public void remove(String docID) {
+		try {
+			index.remove(docID);
+		} catch (IOException e) {
+			// TODO: logs etc
+			e.printStackTrace();
+		}
+	}
+
+	public List<String> retrieve (String query) {
+		String result[] = index.query(query);
+		return new ArrayList<String>(Arrays.asList(result));
+	}
+
+	protected Map<String, String[]> getFields(List<FieldSpec> fields, Reader doc) {
+		Map<String, String[]> idx = new HashMap<String, String[]>();
+		for (FieldSpec fs : fields) {
+			idx.put(fs.name, fs.extract(doc));
+		}
+		return idx;
+	}
+}
Index: src/edu/ucsb/nceas/metacat/index/DocType.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/DocType.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/DocType.java	(revision 7491)
@@ -0,0 +1,84 @@
+package edu.ucsb.nceas.metacat.index;
+
+import org.xml.sax.InputSource;
+
+import javax.xml.xpath.*;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Identify document classes for indexing. Replaces equivalent Spring-based configuration
+ * used by DataONE indexer. It's not clear that we actually need to perfectly mimic this
+ * stuff, but for the now we shall. Note that the replicated DataONE classifications
+ * apply only to DataONE System Metadata documents. Additional classifiers have been
+ * added for plain EML etc.
+ *
+ * There are better ways to configure this stuff, but this is in effect a direct transcript
+ * of the DataONE material. Automatic extraction from Spring configuration is doable, but
+ * not trivial.
+ */
+public class DocType {
+	//
+	private static final XPath xpath = XPathFactory.newInstance().newXPath();
+	private static final List<XPathExpression> d1sys = new ArrayList<XPathExpression>(1);
+	private static final List<XPathExpression> d1eml = new ArrayList<XPathExpression>(4);
+	private static final List<XPathExpression> d1dryad = new ArrayList<XPathExpression>(1);
+	private static final List<XPathExpression> d1fgdc = new ArrayList<XPathExpression>(3);
+	private static final List<XPathExpression> eml = new ArrayList<XPathExpression>(4);
+	static {
+		xpath.setNamespaceContext(new MCXmlNamespace());
+
+		try {
+			d1sys.add(xpath.compile("/" + MCXmlNamespace.D1 + ":systemMetadata"));
+
+			d1eml.add(xpath.compile("/" + MCXmlNamespace.D1 + ":systemMetadata/formatId[text() = 'eml://ecoinformatics.org/eml-2.0.0']"));
+			d1eml.add(xpath.compile("/" + MCXmlNamespace.D1 + ":systemMetadata/formatId[text() = 'eml://ecoinformatics.org/eml-2.0.1']"));
+			d1eml.add(xpath.compile("/" + MCXmlNamespace.D1 + ":systemMetadata/formatId[text() = 'eml://ecoinformatics.org/eml-2.1.1']"));
+			d1eml.add(xpath.compile("/" + MCXmlNamespace.D1 + ":systemMetadata/formatId[text() = 'eml://ecoinformatics.org/eml-2.1.1']"));
+
+			d1dryad.add(xpath.compile("/" + MCXmlNamespace.D1 + ":systemMetadata/formatId[text() = 'http://purl.org/dryad/terms/']"));
+
+			d1fgdc.add(xpath.compile("/" + MCXmlNamespace.D1 + ":systemMetadata/formatId[text() = 'FGDC-STD-001-1998']"));
+			d1fgdc.add(xpath.compile("/" + MCXmlNamespace.D1 + ":systemMetadata/formatId[text() = 'FGDC-STD-001.1-1999']"));
+			d1fgdc.add(xpath.compile("/" + MCXmlNamespace.D1 + ":systemMetadata/formatId[text() = 'FGDC-STD-001.2-1999']"));
+
+			eml.add(xpath.compile("/" + MCXmlNamespace.E200 + ":eml"));
+			eml.add(xpath.compile("/" + MCXmlNamespace.E201 + ":eml"));
+			eml.add(xpath.compile("/" + MCXmlNamespace.E210 + ":eml"));
+			eml.add(xpath.compile("/" + MCXmlNamespace.E211 + ":eml"));
+		} catch (XPathExpressionException e) {
+			// TODO: logs
+			e.printStackTrace();
+		}
+	}
+	public static boolean isSysmeta(Reader in) {
+		return check(d1sys, in);
+	}
+	public static boolean isSyseml(Reader in) {
+		return check(d1eml, in);
+	}
+	public static boolean isSysdryad(Reader in) {
+		return check(d1dryad, in);
+	}
+	public static boolean isSysfgdc(Reader in) {
+		return check(d1fgdc, in);
+	}
+	public static boolean isEml(Reader in) {
+		return check(eml, in);
+	}
+
+	public static boolean check(List<XPathExpression> exprs, Reader in) {
+		InputSource src = new InputSource(in);
+		try {
+			for (XPathExpression x : exprs) {
+				Boolean match = (Boolean) x.evaluate(src, XPathConstants.BOOLEAN);
+				if (match != null && match.booleanValue()) {
+					return true;
+				}
+			}
+		} catch (XPathExpressionException e) {
+		}
+		return false;
+	}
+}
Index: src/edu/ucsb/nceas/metacat/index/Embedded.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/Embedded.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/Embedded.java	(revision 7491)
@@ -0,0 +1,15 @@
+package edu.ucsb.nceas.metacat.index;
+
+import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
+import org.apache.solr.core.CoreContainer;
+
+public class Embedded extends SolrjIndex {
+	Embedded() {
+		super("");
+		// this is just for experiment; proper configuration will be different
+		System.setProperty("solr.solr.home", "/Users/brendan/solrhome/");
+		CoreContainer.Initializer init = new CoreContainer.Initializer();
+		CoreContainer c = init.initialize();
+		solr = new EmbeddedSolrServer(c, "mc-core");
+	}
+}
Index: src/edu/ucsb/nceas/metacat/index/D1Index.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/D1Index.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/D1Index.java	(revision 7491)
@@ -0,0 +1,59 @@
+package edu.ucsb.nceas.metacat.index;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.dataone.cn.indexer.solrhttp.HTTPService;
+import org.dataone.cn.indexer.solrhttp.SolrDoc;
+import org.dataone.cn.indexer.solrhttp.SolrElementAdd;
+import org.dataone.cn.indexer.solrhttp.SolrElementField;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/* * * * disabled for classpath complications * * * */
+public class D1Index implements GenericIndex {
+	protected final DefaultHttpClient client = new DefaultHttpClient();
+	protected final HTTPService solrSvc =
+			new HTTPService(new HttpComponentsClientHttpRequestFactory(this.client));
+	protected String uri = "";
+
+	D1Index(String uri) {
+		this.uri = uri;
+	}
+
+	public void insert(String docID, Map<String, String[]> fields) throws IOException {
+		this.update(docID, fields);
+	}
+
+	public void update(String docID, Map<String, String[]> fields) throws IOException {
+		SolrDoc doc = new SolrDoc();
+		// this works for our purposes, but violates DataONE expectations
+		doc.addField(new SolrElementField(SolrElementField.FIELD_ID, docID));
+		for (String k : fields.keySet()) {
+			for (String v : fields.get(k)) {
+				doc.addField(new SolrElementField(k, v));
+			}
+		}
+		List<SolrDoc> docList = new ArrayList<SolrDoc>(1);
+		docList.add(doc);
+		solrSvc.sendUpdate(this.uri, new SolrElementAdd(docList));
+	}
+
+	public void remove(String docID) {
+		solrSvc.sendSolrDelete(docID);
+	}
+
+	public String[] query(String q) throws IndexOutOfBoundsException {
+		// the indexer's HttpService class doesn't provide general querying -- it's
+		// an indexer only. Query handling is done by separate code in a different
+		// part of the D1 architecture. That code is rather tightly bound to other
+		// D1 elements and consequently challenging to integrate with Metacat.
+		// For this and other reasons I feel that the other index interfaces are
+		// a better choice for Metacat, so as yet this remains incomplete. It is
+		// however possible to continue down this path.
+		return new String[0];
+	}
+}
+*/
\ No newline at end of file
Index: src/edu/ucsb/nceas/metacat/index/MCIndexDocDef.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/MCIndexDocDef.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/MCIndexDocDef.java	(revision 7491)
@@ -0,0 +1,35 @@
+package edu.ucsb.nceas.metacat.index;
+
+import java.util.*;
+
+/*
+ * Schema for document indexing. The Lucene/SOLR model of a 'document' is a bag of named
+ * text objects.
+ */
+public abstract class MCIndexDocDef {
+	protected Set<FieldSpec> fields;
+
+	// do we really want this here? I guess this is the whole question..starting to think not.
+	public abstract boolean applies();
+
+
+	public MCIndexDocDef(Collection<FieldSpec> fields) {
+		this.fields = new HashSet<FieldSpec>(fields);
+	}
+
+	public void add(FieldSpec f) {
+		this.fields.add(f);
+	}
+
+	public void add(Collection<FieldSpec> f) {
+		this.fields.addAll(f);
+	}
+
+	public void remove(FieldSpec f) {
+		this.fields.remove(f);
+	}
+
+	public void remove(Collection<FieldSpec> f) {
+		this.fields.removeAll(f);
+	}
+}
Index: src/edu/ucsb/nceas/metacat/index/MCXmlNamespace.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/MCXmlNamespace.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/MCXmlNamespace.java	(revision 7491)
@@ -0,0 +1,52 @@
+package edu.ucsb.nceas.metacat.index;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ */
+public class MCXmlNamespace implements NamespaceContext {
+	// Namespace prefixes for use in XPath expressions
+	// The literal values assigned here should be distinct but are not significant -- they
+	// may equally be "a" "b" "c" etc as long as the symbolic names are used consistently
+	public static final String E200 = "e200";
+	public static final String E211 = "e211";
+	public static final String E210 = "e210";
+	public static final String E201 = "e201";
+	public static final String D1 = "d1";
+	public static final String ORE = "ore";
+	public static final String DC = "dc";
+	public static final String DCT = "dct";
+	public static final String FOAF = "foaf";
+
+	private static final Map<String, String> prefixes;
+	static {
+		prefixes = new HashMap<String, String>();
+		prefixes.put(E200, "eml://ecoinformatics.org/eml-2.0.0");
+		prefixes.put(E201, "eml://ecoinformatics.org/eml-2.0.1");
+		prefixes.put(E210, "eml://ecoinformatics.org/eml-2.1.0");
+		prefixes.put(E211, "eml://ecoinformatics.org/eml-2.1.1");
+		prefixes.put(D1, "http://ns.dataone.org/service/types/v1");
+		prefixes.put(ORE, "http://www.openarchives.org/ore/terms/");
+		prefixes.put(DC, "http://purl.org/dc/elements/1.1/");
+		prefixes.put(DCT, "http://purl.org/dc/terms/");
+		prefixes.put(FOAF, "http://xmlns.com/foaf/0.1/");
+	}
+	@Override
+	public String getNamespaceURI(String prefix) {
+		String ns = prefixes.get(prefix);
+		return (ns != null) ? ns : XMLConstants.NULL_NS_URI;
+	}
+	@Override
+	public String getPrefix(String namespaceURI) {
+		throw new UnsupportedOperationException();
+	}
+	@Override
+	public Iterator getPrefixes(String namespaceURI) {
+		throw new UnsupportedOperationException();
+	}
+}
+
Index: src/edu/ucsb/nceas/metacat/index/FieldSpec.java
===================================================================
--- src/edu/ucsb/nceas/metacat/index/FieldSpec.java	(nonexistent)
+++ src/edu/ucsb/nceas/metacat/index/FieldSpec.java	(revision 7491)
@@ -0,0 +1,22 @@
+package edu.ucsb.nceas.metacat.index;
+
+import org.w3c.dom.Document;
+import sun.beans.editors.ByteEditor;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.Reader;
+
+/**
+ */
+public abstract class FieldSpec {
+	public final String name;
+
+	public FieldSpec(String name) {
+		this.name = name;
+	}
+	/* */
+	public abstract String[] extract(final Reader s);
+
+	// public abstract String extract(ByteArrayInputStream s);
+}
