提交 560d0380 authored 作者: Thomas Mueller's avatar Thomas Mueller

Lucene 3.x support was added in the source code, however it is not yet enabled by default.

上级 55d3d9e1
......@@ -16,17 +16,14 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.DateTools;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexModifier;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Searcher;
......@@ -42,6 +39,19 @@ import org.h2.util.New;
import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
//## Java 1.4 end ##
//## LUCENE2 begin ##
import org.apache.lucene.index.IndexModifier;
import org.apache.lucene.search.Hits;
//## LUCENE2 end ##
/*## LUCENE3 begin ##
import java.io.File;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Version;
import org.apache.lucene.index.IndexWriter;
//## LUCENE3 end ##*/
/**
* This class implements the full text search based on Apache Lucene.
......@@ -55,7 +65,7 @@ public class FullTextLucene extends FullText {
protected static final boolean STORE_DOCUMENT_TEXT_IN_INDEX = Boolean.getBoolean("h2.storeDocumentTextInIndex");
//## Java 1.4 begin ##
private static final HashMap<String, IndexModifier> INDEX_MODIFIERS = New.hashMap();
private static final HashMap<String, IndexAccess> INDEX_ACCESS = New.hashMap();
private static final String TRIGGER_PREFIX = "FTL_";
private static final String SCHEMA = "FTL";
private static final String LUCENE_FIELD_DATA = "_DATA";
......@@ -98,7 +108,7 @@ public class FullTextLucene extends FullText {
stat.execute("CREATE ALIAS IF NOT EXISTS FTL_REINDEX FOR \"" + FullTextLucene.class.getName() + ".reindex\"");
stat.execute("CREATE ALIAS IF NOT EXISTS FTL_DROP_ALL FOR \"" + FullTextLucene.class.getName() + ".dropAll\"");
try {
getIndexModifier(conn);
getIndexAccess(conn);
} catch (SQLException e) {
throw convertException(e);
}
......@@ -140,7 +150,7 @@ public class FullTextLucene extends FullText {
removeAllTriggers(conn, TRIGGER_PREFIX);
removeIndexFiles(conn);
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM "+SCHEMA+".INDEXES");
ResultSet rs = stat.executeQuery("SELECT * FROM " + SCHEMA + ".INDEXES");
while (rs.next()) {
String schema = rs.getString("SCHEMA");
String table = rs.getString("TABLE");
......@@ -247,28 +257,43 @@ public class FullTextLucene extends FullText {
}
/**
* Get the index modifier for the given connection.
* Get the index writer/searcher wrapper for the given connection.
*
* @param conn the connection
* @return the index modifier
* @return the index access wrapper
*/
protected static IndexModifier getIndexModifier(Connection conn) throws SQLException {
protected static IndexAccess getIndexAccess(Connection conn) throws SQLException {
String path = getIndexPath(conn);
IndexModifier indexer;
synchronized (INDEX_MODIFIERS) {
indexer = INDEX_MODIFIERS.get(path);
if (indexer == null) {
synchronized (INDEX_ACCESS) {
IndexAccess access = INDEX_ACCESS.get(path);
if (access == null) {
try {
//## LUCENE2 begin ##
boolean recreate = !IndexReader.indexExists(path);
Analyzer analyzer = new StandardAnalyzer();
indexer = new IndexModifier(path, analyzer, recreate);
access = new IndexAccess();
access.modifier = new IndexModifier(path, analyzer, recreate);
//## LUCENE2 end ##
/*## LUCENE3 begin ##
File f = new File(path);
Directory indexDir = FSDirectory.open(f);
boolean recreate = !IndexReader.indexExists(indexDir);
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
IndexWriter writer = new IndexWriter(indexDir, analyzer,
recreate, IndexWriter.MaxFieldLength.UNLIMITED);
//see http://wiki.apache.org/lucene-java/NearRealtimeSearch
IndexReader reader = writer.getReader();
access = new IndexAccess();
access.writer = writer;
access.searcher = new IndexSearcher(reader);
//## LUCENE3 end ##*/
} catch (IOException e) {
throw convertException(e);
}
INDEX_MODIFIERS.put(path, indexer);
INDEX_ACCESS.put(path, access);
}
return access;
}
return indexer;
}
/**
......@@ -318,25 +343,31 @@ public class FullTextLucene extends FullText {
private static void removeIndexFiles(Connection conn) throws SQLException {
String path = getIndexPath(conn);
IndexModifier index = INDEX_MODIFIERS.get(path);
if (index != null) {
removeIndexModifier(index, path);
IndexAccess access = INDEX_ACCESS.get(path);
if (access != null) {
removeIndexAccess(access, path);
}
FileSystem.getInstance(path).deleteRecursive(path, false);
}
/**
* Close the index modifier and remove it from the index modifier set.
* Close the index writer and searcher and remove them from the index access set.
*
* @param indexModifier the index modifier
* @param access the index writer/searcher wrapper
* @param indexPath the index path
*/
protected static void removeIndexModifier(IndexModifier indexModifier, String indexPath) throws SQLException {
synchronized (INDEX_MODIFIERS) {
protected static void removeIndexAccess(IndexAccess access, String indexPath) throws SQLException {
synchronized (INDEX_ACCESS) {
try {
INDEX_MODIFIERS.remove(indexPath);
indexModifier.flush();
indexModifier.close();
INDEX_ACCESS.remove(indexPath);
//## LUCENE2 begin ##
access.modifier.flush();
access.modifier.close();
//## LUCENE2 end ##
/*## LUCENE3 begin ##
access.searcher.close();
access.writer.close();
//## LUCENE3 end ##*/
} catch (Exception e) {
throw convertException(e);
}
......@@ -362,10 +393,11 @@ public class FullTextLucene extends FullText {
if (text == null || text.trim().length() == 0) {
return result;
}
String path = getIndexPath(conn);
try {
IndexModifier indexer = getIndexModifier(conn);
indexer.flush();
IndexAccess access = getIndexAccess(conn);
//## LUCENE2 begin ##
access.modifier.flush();
String path = getIndexPath(conn);
IndexReader reader = IndexReader.open(path);
Analyzer analyzer = new StandardAnalyzer();
Searcher searcher = new IndexSearcher(reader);
......@@ -379,6 +411,31 @@ public class FullTextLucene extends FullText {
for (int i = 0; i < limit && i + offset < max; i++) {
Document doc = hits.doc(i + offset);
float score = hits.score(i + offset);
//## LUCENE2 end ##
/*## LUCENE3 begin ##
// take a reference as the searcher may change
Searcher searcher = access.searcher;
// reuse the same analyzer; it's thread-safe;
// also allows subclasses to control the analyzer used.
Analyzer analyzer = access.writer.getAnalyzer();
QueryParser parser = new QueryParser(Version.LUCENE_30,
LUCENE_FIELD_DATA, analyzer);
Query query = parser.parse(text);
// Lucene 3 insists on a hard limit and will not provide
// a total hits value. Take at least 100 which is
// an optimal limit for Lucene as any more
// will trigger writing results to disk.
int maxResults = (limit == 0 ? 100 : limit) + offset;
TopDocs docs = searcher.search(query, maxResults);
if (limit == 0) {
limit = docs.totalHits;
}
for (int i = 0; i < limit && i + offset < docs.totalHits
&& i + offset < docs.scoreDocs.length; i++) {
ScoreDoc sd = docs.scoreDocs[i + offset];
Document doc = searcher.doc(sd.doc);
float score = sd.score;
//## LUCENE3 end ##*/
String q = doc.get(LUCENE_FIELD_QUERY);
if (data) {
int idx = q.indexOf(" WHERE ");
......@@ -401,8 +458,10 @@ public class FullTextLucene extends FullText {
result.addRow(q, score);
}
}
//## LUCENE2 begin ##
// TODO keep it open if possible
reader.close();
//## LUCENE2 end ##
} catch (Exception e) {
throw convertException(e);
}
......@@ -427,7 +486,7 @@ public class FullTextLucene extends FullText {
protected String[] columns;
protected int[] columnTypes;
protected String indexPath;
protected IndexModifier indexModifier;
protected IndexAccess indexAccess;
//## Java 1.4 end ##
/**
......@@ -439,7 +498,7 @@ public class FullTextLucene extends FullText {
this.schema = schemaName;
this.table = tableName;
this.indexPath = getIndexPath(conn);
this.indexModifier = getIndexModifier(conn);
this.indexAccess = getIndexAccess(conn);
ArrayList<String> keyList = New.arrayList();
DatabaseMetaData meta = conn.getMetaData();
ResultSet rs = meta.getColumns(null,
......@@ -525,9 +584,9 @@ public class FullTextLucene extends FullText {
*/
//## Java 1.4 begin ##
public void close() throws SQLException {
if (indexModifier != null) {
removeIndexModifier(indexModifier, indexPath);
indexModifier = null;
if (indexAccess != null) {
removeIndexAccess(indexAccess, indexPath);
indexAccess = null;
}
}
//## Java 1.4 end ##
......@@ -545,11 +604,15 @@ public class FullTextLucene extends FullText {
* @param row the row
*/
protected void insert(Object[] row) throws SQLException {
//## LUCENE2 begin ##
String query = getQuery(row);
Document doc = new Document();
doc.add(new Field(LUCENE_FIELD_QUERY, query, Field.Store.YES, Field.Index.UN_TOKENIZED));
doc.add(new Field(LUCENE_FIELD_QUERY, query,
Field.Store.YES, Field.Index.UN_TOKENIZED));
long time = System.currentTimeMillis();
doc.add(new Field(LUCENE_FIELD_MODIFIED, DateTools.timeToString(time, DateTools.Resolution.SECOND), Field.Store.YES, Field.Index.UN_TOKENIZED));
doc.add(new Field(LUCENE_FIELD_MODIFIED,
DateTools.timeToString(time, DateTools.Resolution.SECOND),
Field.Store.YES, Field.Index.UN_TOKENIZED));
StatementBuilder buff = new StatementBuilder();
for (int index : indexColumns) {
String columnName = columns[index];
......@@ -559,18 +622,59 @@ public class FullTextLucene extends FullText {
if (columnName.startsWith(LUCENE_FIELD_COLUMN_PREFIX)) {
columnName = LUCENE_FIELD_COLUMN_PREFIX + columnName;
}
doc.add(new Field(columnName, data, Field.Store.NO, Field.Index.TOKENIZED));
doc.add(new Field(columnName, data,
Field.Store.NO, Field.Index.TOKENIZED));
buff.appendExceptFirst(" ");
buff.append(data);
}
Field.Store storeText = STORE_DOCUMENT_TEXT_IN_INDEX ? Field.Store.YES : Field.Store.NO;
Field.Store storeText = STORE_DOCUMENT_TEXT_IN_INDEX ?
Field.Store.YES : Field.Store.NO;
doc.add(new Field(LUCENE_FIELD_DATA, buff.toString(), storeText,
Field.Index.TOKENIZED));
try {
indexModifier.addDocument(doc);
indexAccess.modifier.addDocument(doc);
} catch (IOException e) {
throw convertException(e);
}
//## LUCENE2 end ##
/*## LUCENE3 begin ##
String query = getQuery(row);
Document doc = new Document();
doc.add(new Field(LUCENE_FIELD_QUERY, query,
Field.Store.YES, Field.Index.NOT_ANALYZED));
long time = System.currentTimeMillis();
doc.add(new Field(LUCENE_FIELD_MODIFIED,
DateTools.timeToString(time, DateTools.Resolution.SECOND),
Field.Store.YES, Field.Index.NOT_ANALYZED));
StatementBuilder buff = new StatementBuilder();
for (int index : indexColumns) {
String columnName = columns[index];
String data = asString(row[index], columnTypes[index]);
// column names that start with _
// must be escaped to avoid conflicts
// with internal field names (_DATA, _QUERY, _modified)
if (columnName.startsWith(LUCENE_FIELD_COLUMN_PREFIX)) {
columnName = LUCENE_FIELD_COLUMN_PREFIX + columnName;
}
doc.add(new Field(columnName, data,
Field.Store.NO, Field.Index.ANALYZED));
buff.appendExceptFirst(" ");
buff.append(data);
}
Field.Store storeText = STORE_DOCUMENT_TEXT_IN_INDEX ?
Field.Store.YES : Field.Store.NO;
doc.add(new Field(LUCENE_FIELD_DATA, buff.toString(), storeText,
Field.Index.ANALYZED));
try {
indexAccess.writer.addDocument(doc);
indexAccess.writer.commit();
//Recreate Searcher with the IndexWriter's reader.
IndexReader reader = indexAccess.writer.getReader();
indexAccess.searcher = new IndexSearcher(reader);
} catch (IOException e) {
throw convertException(e);
}
//## LUCENE3 end ##*/
}
/**
......@@ -582,7 +686,12 @@ public class FullTextLucene extends FullText {
String query = getQuery(row);
try {
Term term = new Term(LUCENE_FIELD_QUERY, query);
indexModifier.deleteDocuments(term);
//## LUCENE2 begin ##
indexAccess.modifier.deleteDocuments(term);
//## LUCENE2 end ##
/*## LUCENE3 begin ##
indexAccess.writer.deleteDocuments(term);
//## LUCENE3 end ##*/
} catch (IOException e) {
throw convertException(e);
}
......@@ -608,4 +717,31 @@ public class FullTextLucene extends FullText {
}
}
/**
* A wrapper for the Lucene writer and searcher.
*/
static class IndexAccess {
/**
* The index modified.
*/
//## LUCENE2 begin ##
IndexModifier modifier;
//## LUCENE2 end ##
/**
* The index writer.
*/
/*## LUCENE3 begin ##
IndexWriter writer;
//## LUCENE3 end ##*/
/**
* The index searcher.
*/
/*## LUCENE3 begin ##
Searcher searcher;
//## LUCENE3 end ##*/
}
}
......@@ -23,6 +23,11 @@ import org.h2.test.TestBase;
*/
public class TestFullText extends TestBase {
/**
* The words used in this test.
*/
static final String[] KNOWN_WORDS = { "skiing", "balance", "storage", "water", "train" };
/**
* Run just this test.
*
......@@ -38,7 +43,8 @@ public class TestFullText extends TestBase {
if (config.memory) {
return;
}
testMultiThreaded();
testMultiThreaded(true);
testMultiThreaded(false);
testStreamLob();
test(false, "VARCHAR");
test(false, "CLOB");
......@@ -79,6 +85,8 @@ public class TestFullText extends TestBase {
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
stat.execute("INSERT INTO TEST VALUES(1, 'Hello World')");
stat.execute("CALL " + prefix + "_CREATE_INDEX('PUBLIC', 'TEST', NULL)");
ResultSet rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Hello', 0, 0)");
assertTrue(rs.next());
stat.execute("UPDATE TEST SET NAME=NULL WHERE ID=1");
stat.execute("UPDATE TEST SET NAME='Hello World' WHERE ID=1");
conn.setAutoCommit(false);
......@@ -87,7 +95,7 @@ public class TestFullText extends TestBase {
conn.close();
conn = getConnection("fullTextTransaction");
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Hello', 0, 0)");
rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Hello', 0, 0)");
assertTrue(rs.next());
rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Moon', 0, 0)");
assertFalse(rs.next());
......@@ -97,7 +105,9 @@ public class TestFullText extends TestBase {
FileSystem.getInstance(getBaseDir()).deleteRecursive(getBaseDir() + "/fullTextTransaction", false);
}
private void testMultiThreaded() throws Exception {
private void testMultiThreaded(boolean lucene) throws Exception {
final String prefix = lucene ? "FTL" : "FT";
trace("Testing multithreaded " + prefix);
deleteDb("fullText");
final boolean[] stop = { false };
final Exception[] exception = { null };
......@@ -108,49 +118,67 @@ public class TestFullText extends TestBase {
// getConnection("fullText;MULTI_THREADED=1;LOCK_TIMEOUT=10000");
final Connection conn = getConnection("fullText");
Statement stat = conn.createStatement();
stat.execute("CREATE ALIAS IF NOT EXISTS FT_INIT FOR \"org.h2.fulltext.FullText.init\"");
stat.execute("CALL FT_INIT()");
stat.execute("CREATE ALIAS IF NOT EXISTS FT_INIT FOR \"org.h2.fulltext.FullText.init\"");
stat.execute("CALL FT_INIT()");
String className = lucene ? "FullTextLucene" : "FullText";
stat.execute("CREATE ALIAS IF NOT EXISTS " + prefix + "_INIT FOR \"org.h2.fulltext." + className + ".init\"");
stat.execute("CALL " + prefix + "_INIT()");
stat.execute("CREATE ALIAS IF NOT EXISTS " + prefix + "_INIT FOR \"org.h2.fulltext." + className + ".init\"");
stat.execute("CALL " + prefix + "_INIT()");
final String tableName = "TEST" + i;
stat.execute("CREATE TABLE " + tableName + "(ID INT PRIMARY KEY, DATA VARCHAR)");
FullText.createIndex(conn, "PUBLIC", tableName, null);
stat.execute("CALL " + prefix + "_CREATE_INDEX('PUBLIC', '" + tableName + "', NULL)");
threads[i] = new Thread() {
public void run() {
trace("starting thread " + Thread.currentThread());
try {
PreparedStatement prep = conn.prepareStatement("INSERT INTO " + tableName + " VALUES(?, ?)");
Statement stat = conn.createStatement();
Random random = new Random();
int x = 0;
while (!stop[0]) {
trace("stop[0] = " + stop[0] + " for " + Thread.currentThread());
StringBuilder buff = new StringBuilder();
for (int j = 0; j < 1000; j++) {
buff.append(" " + random.nextInt(10000));
buff.append(" x" + j);
buff.append(" ").append(random.nextInt(10000));
buff.append(" x").append(j);
buff.append(" ").append(KNOWN_WORDS[j % KNOWN_WORDS.length]);
}
prep.setInt(1, x);
prep.setString(2, buff.toString());
prep.execute();
x++;
for (String knownWord : KNOWN_WORDS) {
trace("searching for " + knownWord + " with " + Thread.currentThread());
ResultSet rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('" + knownWord + "', 0, 0)");
assertTrue(rs.next());
}
}
trace("closing connection");
conn.close();
} catch (SQLException e) {
exception[0] = e;
} finally {
trace("completed thread " + Thread.currentThread());
}
}
};
}
for (Thread t : threads) {
t.setDaemon(true);
t.start();
}
trace("sleeping");
Thread.sleep(1000);
trace("setting stop to true");
stop[0] = true;
for (Thread t : threads) {
trace("joining " + t);
t.join();
trace("done joining " + t);
}
if (exception[0] != null) {
throw exception[0];
}
}
private void testStreamLob() throws SQLException {
......@@ -374,8 +402,6 @@ public class TestFullText extends TestBase {
stat = conn.createStatement();
rs = stat.executeQuery("SELECT * FROM " + prefix + "SEARCH('World', 0, 0)");
stat.execute("CALL " + prefix + "DROP_ALL()");
stat.executeQuery("SELECT * FROM " + prefix + "SEARCH('World', 2, 1)");
stat.execute("CALL " + prefix + "DROP_ALL()");
conn.close();
......
......@@ -105,7 +105,7 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/emma-2.0.5312.jar" +
File.pathSeparator + "ext/postgresql-8.3-603.jdbc3.jar" +
File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/lucene-core-2.2.0.jar" +
File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar" +
File.pathSeparator + "ext/slf4j-api-1.5.0.jar";
exec("java", args("-Xmx128m", "-cp", cp, "emma", "run",
......@@ -127,6 +127,9 @@ public class Build extends BuildBase {
} else {
SwitchSource.main("-dir", "src", "-version", version);
}
if (System.getProperty("lucene") != null) {
SwitchSource.main("-dir", "src", "-LUCENE2", "-LUCENE3", "+LUCENE" + getLuceneVersion());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
......@@ -139,7 +142,7 @@ public class Build extends BuildBase {
download();
String classpath = "temp" +
File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/lucene-core-2.2.0.jar" +
File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/slf4j-api-1.5.0.jar" +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar" +
File.pathSeparator + System.getProperty("java.home") + "/../lib/tools.jar";
......@@ -218,9 +221,15 @@ public class Build extends BuildBase {
download("ext/servlet-api-2.4.jar",
"http://repo1.maven.org/maven2/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar",
"3fc542fe8bb8164e8d3e840fe7403bc0518053c0");
if (getLuceneVersion() == 3) {
download("ext/lucene-core-3.0.2.jar",
"http://repo1.maven.org/maven2/org/apache/lucene/lucene-core/3.0.2/lucene-core-3.0.2.jar",
"c2b48995ab855c1b9ea13867a0f976c994e0105d");
} else {
download("ext/lucene-core-2.2.0.jar",
"http://repo1.maven.org/maven2/org/apache/lucene/lucene-core/2.2.0/lucene-core-2.2.0.jar",
"47b6eee2e17bd68911e7045896a1c09de0b2dda8");
}
download("ext/slf4j-api-1.5.0.jar",
"http://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.5.0/slf4j-api-1.5.0.jar",
"b2df265d02350ecfe87b6c1773c7c4fab2b33505");
......@@ -240,6 +249,14 @@ public class Build extends BuildBase {
return getStaticValue("org.h2.engine.Constants", "getVersion");
}
private String getLuceneJar() {
return "lucene-core-" + (getLuceneVersion() == 2 ? "2.2.0" : "3.0.2") + ".jar";
}
private int getLuceneVersion() {
return Integer.parseInt(System.getProperty("lucene", "2"));
}
private String getJarSuffix() {
return "-" + getVersion() + ".jar";
}
......@@ -382,7 +399,7 @@ public class Build extends BuildBase {
mkdir("docs/javadoc");
javadoc("-sourcepath", "src/main", "org.h2.jdbc", "org.h2.jdbcx",
"org.h2.tools", "org.h2.api", "org.h2.constant", "org.h2.fulltext",
"-classpath", "ext/lucene-core-2.2.0.jar",
"-classpath", "ext/" + getLuceneJar(),
"-docletpath", "bin" + File.pathSeparator + "temp",
"-doclet", "org.h2.build.doclet.Doclet");
copy("docs/javadoc", files("src/docsrc/javadoc"), "src/docsrc/javadoc");
......@@ -402,7 +419,7 @@ public class Build extends BuildBase {
"/../lib/tools.jar" +
File.pathSeparator + "ext/slf4j-api-1.5.0.jar" +
File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/lucene-core-2.2.0.jar" +
File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar",
"-subpackages", "org.h2",
"-exclude", "org.h2.test.jaqu:org.h2.jaqu");
......@@ -412,7 +429,7 @@ public class Build extends BuildBase {
"-classpath", System.getProperty("java.home") + "/../lib/tools.jar" +
File.pathSeparator + "ext/slf4j-api-1.5.0.jar" +
File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/lucene-core-2.2.0.jar" +
File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar",
"-subpackages", "org.h2",
"-exclude", "org.h2.test.jaqu:org.h2.jaqu",
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论