You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by rm...@apache.org on 2013/01/11 15:39:47 UTC

svn commit: r1432065 [5/5] - in /lucene/dev/branches/lucene4547: ./ lucene/ lucene/analysis/ lucene/analysis/common/ lucene/analysis/common/src/test/org/apache/lucene/analysis/core/ lucene/analysis/kuromoji/src/tools/java/org/apache/lucene/analysis/ja/...

Modified: lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java Fri Jan 11 14:39:45 2013
@@ -17,8 +17,21 @@
 
 package org.apache.solr.search;
 
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.DisjunctionMaxQuery;
+import org.apache.lucene.search.FuzzyQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.util.AbstractSolrTestCase;
+import org.apache.solr.util.SolrPluginUtils;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -510,37 +523,42 @@ public class TestExtendedDismaxParser ex
   
   public void testCyclicAliasing() throws Exception {
     try {
-      h.query(req("defType","edismax", "q","ignore_exception", "qf","who", "f.who.qf","name","f.name.qf","who"));
-      fail("Simple cyclic alising");
-    } catch (SolrException e) {
-      assertTrue(e.getCause().getMessage().contains("Field aliases lead to a cycle"));
-    }
-    
-    try {
-      h.query(req("defType","edismax", "q","ignore_exception", "qf","who", "f.who.qf","name","f.name.qf","myalias", "f.myalias.qf","who"));
-      fail();
-    } catch (SolrException e) {
-      assertTrue(e.getCause().getMessage().contains("Field aliases lead to a cycle"));
-    }
-    
-    try {
-      h.query(req("defType","edismax", "q","ignore_exception", "qf","field1", "f.field1.qf","field2 field3","f.field2.qf","field4 field5", "f.field4.qf","field5", "f.field5.qf","field6", "f.field3.qf","field6"));
-    } catch (SolrException e) {
-      fail("This is not cyclic alising");
-    }
-    
-    try {
-      h.query(req("defType","edismax", "q","ignore_exception", "qf","field1", "f.field1.qf","field2 field3", "f.field2.qf","field4 field5", "f.field4.qf","field5", "f.field5.qf","field4"));
-      fail();
-    } catch (SolrException e) {
-      assertTrue(e.getCause().getMessage().contains("Field aliases lead to a cycle"));
-    }
-    
-    try {
-      h.query(req("defType","edismax", "q","who:(Zapp Pig) ignore_exception", "qf","field1", "f.who.qf","name","f.name.qf","myalias", "f.myalias.qf","who"));
-      fail();
-    } catch (SolrException e) {
-      assertTrue(e.getCause().getMessage().contains("Field aliases lead to a cycle"));
+      ignoreException(".*Field aliases lead to a cycle.*");
+      try {
+        h.query(req("defType","edismax", "q","blarg", "qf","who", "f.who.qf","name","f.name.qf","who"));
+        fail("Simple cyclic alising not detected");
+      } catch (SolrException e) {
+        assertTrue(e.getCause().getMessage().contains("Field aliases lead to a cycle"));
+      }
+      
+      try {
+        h.query(req("defType","edismax", "q","blarg", "qf","who", "f.who.qf","name","f.name.qf","myalias", "f.myalias.qf","who"));
+        fail("Cyclic alising not detected");
+      } catch (SolrException e) {
+        assertTrue(e.getCause().getMessage().contains("Field aliases lead to a cycle"));
+      }
+      
+      try {
+        h.query(req("defType","edismax", "q","blarg", "qf","field1", "f.field1.qf","field2 field3","f.field2.qf","field4 field5", "f.field4.qf","field5", "f.field5.qf","field6", "f.field3.qf","field6"));
+      } catch (SolrException e) {
+        fail("This is not cyclic alising");
+      }
+      
+      try {
+        h.query(req("defType","edismax", "q","blarg", "qf","field1", "f.field1.qf","field2 field3", "f.field2.qf","field4 field5", "f.field4.qf","field5", "f.field5.qf","field4"));
+        fail("Cyclic alising not detected");
+      } catch (SolrException e) {
+        assertTrue(e.getCause().getMessage().contains("Field aliases lead to a cycle"));
+      }
+      
+      try {
+        h.query(req("defType","edismax", "q","who:(Zapp Pig)", "qf","field1", "f.who.qf","name","f.name.qf","myalias", "f.myalias.qf","who"));
+        fail("Cyclic alising not detected");
+      } catch (SolrException e) {
+        assertTrue(e.getCause().getMessage().contains("Field aliases lead to a cycle"));
+      }
+    } finally {
+      resetExceptionIgnores();
     }
   }
 
@@ -930,4 +948,157 @@ public class TestExtendedDismaxParser ex
             "defType", "edismax")
         , "*[count(//doc)=1]");
   }
+  
+  public void testEdismaxSimpleExtension() throws SyntaxError {
+    ModifiableSolrParams params = new ModifiableSolrParams();
+    params.set("q", "foo bar");
+    params.set("qf", "subject title^5");
+    params.set("qf_fr", "subject_fr title_fr^5");
+    params.set("qf_en", "subject_en title_en^5");
+    params.set("qf_es", "subject_es title_es^5");
+    
+    MultilanguageQueryParser parser = new MultilanguageQueryParser("foo bar", new ModifiableSolrParams(), params, req(params));
+    Query query = parser.parse();
+    assertNotNull(query);
+    assertTrue(containsClause(query, "title", "foo", 5, false));
+    assertTrue(containsClause(query, "title", "bar", 5, false));
+    assertTrue(containsClause(query, "subject", "foo", 1, false));
+    assertTrue(containsClause(query, "subject", "bar", 1, false));
+    
+    params.set("language", "es");
+    parser = new MultilanguageQueryParser("foo bar", new ModifiableSolrParams(), params, req(params));
+    query = parser.parse();
+    assertNotNull(query);
+    assertTrue(containsClause(query, "title_es", "foo", 5, false));
+    assertTrue(containsClause(query, "title_es", "bar", 5, false));
+    assertTrue(containsClause(query, "subject_es", "foo", 1, false));
+    assertTrue(containsClause(query, "subject_es", "bar", 1, false));
+    
+    FuzzyDismaxQParser parser2 = new FuzzyDismaxQParser("foo bar absence", new ModifiableSolrParams(), params, req(params));
+    query = parser2.parse();
+    assertNotNull(query);
+    assertTrue(containsClause(query, "title", "foo", 5, false));
+    assertTrue(containsClause(query, "title", "bar", 5, false));
+    assertTrue(containsClause(query, "title", "absence", 5, true));
+    
+  }
+
+  private boolean containsClause(Query query, String field, String value,
+      int boost, boolean fuzzy) {
+    
+    if(query instanceof BooleanQuery) {
+      return containsClause((BooleanQuery)query, field, value, boost, fuzzy);
+    }
+    if(query instanceof DisjunctionMaxQuery) {
+      return containsClause((DisjunctionMaxQuery)query, field, value, boost, fuzzy);
+    }
+    if(query instanceof TermQuery && !fuzzy) {
+      return containsClause((TermQuery)query, field, value, boost);
+    }
+    if(query instanceof FuzzyQuery && fuzzy) {
+      return containsClause((FuzzyQuery)query, field, value, boost);
+    }
+    return false;
+  }
+
+  private boolean containsClause(FuzzyQuery query, String field, String value,
+      int boost) {
+    if(query.getTerm().field().equals(field) && 
+       query.getTerm().bytes().utf8ToString().equals(value) && 
+       query.getBoost() == boost) {
+      return true;
+    }
+    return false;
+  }
+
+  private boolean containsClause(BooleanQuery query, String field, String value, int boost, boolean fuzzy) {
+    for(BooleanClause clause:query.getClauses()) {
+      if(containsClause(clause.getQuery(), field, value, boost, fuzzy)) {
+        return true;
+      }
+    }
+    return false;
+  }
+  
+  private boolean containsClause(TermQuery query, String field, String value, int boost) {
+    if(query.getTerm().field().equals(field) && 
+       query.getTerm().bytes().utf8ToString().equals(value) && 
+       query.getBoost() == boost) {
+      return true;
+    }
+    return false;
+  }
+  
+  private boolean containsClause(DisjunctionMaxQuery query, String field, String value, int boost, boolean fuzzy) {
+    for(Query disjunct:query.getDisjuncts()) {
+      if(containsClause(disjunct, field, value, boost, fuzzy)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  class MultilanguageQueryParser extends ExtendedDismaxQParser {
+
+    public MultilanguageQueryParser(String qstr, SolrParams localParams,
+        SolrParams params, SolrQueryRequest req) {
+      super(qstr, localParams, params, req);
+    }
+    
+    @Override
+    protected ExtendedDismaxConfiguration createConfiguration(String qstr,
+        SolrParams localParams, SolrParams params, SolrQueryRequest req) {
+      return new MultilanguageDismaxConfiguration(localParams, params, req);
+    }
+    
+    class MultilanguageDismaxConfiguration extends ExtendedDismaxConfiguration {
+
+      public MultilanguageDismaxConfiguration(SolrParams localParams,
+          SolrParams params, SolrQueryRequest req) {
+        super(localParams, params, req);
+        String language = params.get("language");
+        if(language != null) {
+          super.queryFields = SolrPluginUtils.parseFieldBoosts(solrParams.getParams("qf_" + language)); 
+        }
+      }
+      
+    }
+    
+  }
+  
+  
+  
+  class FuzzyDismaxQParser extends ExtendedDismaxQParser {
+
+    public FuzzyDismaxQParser(String qstr, SolrParams localParams,
+        SolrParams params, SolrQueryRequest req) {
+      super(qstr, localParams, params, req);
+    }
+    
+    @Override
+    protected ExtendedSolrQueryParser createEdismaxQueryParser(QParser qParser,
+        String field) {
+      return new FuzzyQueryParser(qParser, field);
+    }
+    
+    class FuzzyQueryParser extends ExtendedSolrQueryParser{
+      
+      private Set<String> frequentlyMisspelledWords;
+
+      public FuzzyQueryParser(QParser parser, String defaultField) {
+        super(parser, defaultField);
+        frequentlyMisspelledWords = new HashSet<String>();
+        frequentlyMisspelledWords.add("absence");
+      }
+      
+      @Override
+      protected Query getFieldQuery(String field,
+          String val, boolean quoted) throws SyntaxError {
+        if(frequentlyMisspelledWords.contains(val)) {
+          return getFuzzyQuery(field, val, 0.75F);
+        }
+        return super.getFieldQuery(field, val, quoted);
+      }
+    }
+  }
 }

Modified: lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/servlet/DirectSolrConnectionTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/servlet/DirectSolrConnectionTest.java?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/servlet/DirectSolrConnectionTest.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/servlet/DirectSolrConnectionTest.java Fri Jan 11 14:39:45 2013
@@ -17,6 +17,8 @@
 
 package org.apache.solr.servlet;
 
+import java.net.URLEncoder;
+
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.util.AbstractSolrTestCase;
 import org.junit.BeforeClass;
@@ -74,7 +76,7 @@ public class DirectSolrConnectionTest ex
     
     // Test using the Stream body parameter
     for( String cmd : cmds ) {
-      direct.request( "/update?"+CommonParams.STREAM_BODY+"="+cmd, null );
+      direct.request( "/update?"+CommonParams.STREAM_BODY+"="+URLEncoder.encode(cmd, "UTF-8"), null );
     }
     String got = direct.request( getIt, null );
     assertTrue( got.indexOf( value ) > 0 );

Modified: lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java (original)
+++ lucene/dev/branches/lucene4547/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java Fri Jan 11 14:39:45 2013
@@ -25,7 +25,6 @@ import java.io.ByteArrayInputStream;
 import java.net.HttpURLConnection;
 import java.net.SocketTimeoutException;
 import java.net.URL;
-import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -115,7 +114,6 @@ public class SolrRequestParserTest exten
   @Test
   public void testStreamURL() throws Exception
   {
-    boolean ok = false;
     String url = "http://www.apache.org/dist/lucene/solr/";
     byte[] bytes = null;
     try {
@@ -152,19 +150,51 @@ public class SolrRequestParserTest exten
   }
   
   @Test
-  public void testUrlParamParsing()
+  public void testUrlParamParsing() throws Exception
   {
-    String[][] teststr = new String[][] {
+    final String[][] teststr = new String[][] {
       { "this is simple", "this%20is%20simple" },
       { "this is simple", "this+is+simple" },
       { "\u00FC", "%C3%BC" },   // lower-case "u" with diaeresis/umlaut
       { "\u0026", "%26" },      // &
-      { "\u20AC", "%E2%82%AC" } // euro
+      { "", "" },               // empty
+      { "\u20AC", "%E2%82%ac" } // euro, also with lowercase escapes
     };
     
     for( String[] tst : teststr ) {
-      MultiMapSolrParams params = SolrRequestParsers.parseQueryString( "val="+tst[1] );
+      SolrParams params = SolrRequestParsers.parseQueryString( "val="+tst[1] );
       assertEquals( tst[0], params.get( "val" ) );
+      params = SolrRequestParsers.parseQueryString( "val="+tst[1]+"&" );
+      assertEquals( tst[0], params.get( "val" ) );
+      params = SolrRequestParsers.parseQueryString( "&&val="+tst[1]+"&" );
+      assertEquals( tst[0], params.get( "val" ) );
+      params = SolrRequestParsers.parseQueryString( "&&val="+tst[1]+"&&&val="+tst[1]+"&" );
+      assertArrayEquals(new String[]{tst[0],tst[0]}, params.getParams("val") );
+   }
+    
+    SolrParams params = SolrRequestParsers.parseQueryString("val");
+    assertEquals("", params.get("val"));
+    
+    params = SolrRequestParsers.parseQueryString("val&foo=bar=bar&muh&");
+    assertEquals("", params.get("val"));
+    assertEquals("bar=bar", params.get("foo"));
+    assertEquals("", params.get("muh"));
+    
+    final String[] invalid = {
+      "q=h%FCllo",     // non-UTF-8
+      "q=h\u00FCllo",  // encoded string is not pure US-ASCII
+      "q=hallo%",      // incomplete escape
+      "q=hallo%1",     // incomplete escape
+      "q=hallo%XX123", // invalid digit 'X' in escape
+      "=hallo"         // missing key
+    };
+    for (String s : invalid) {
+      try {
+        SolrRequestParsers.parseQueryString(s);
+        fail("Should throw SolrException");
+      } catch (SolrException se) {
+        // pass
+      }
     }
   }
   
@@ -172,7 +202,7 @@ public class SolrRequestParserTest exten
   public void testStandardParseParamsAndFillStreams() throws Exception
   {
     final String getParams = "qt=%C3%BC&dup=foo", postParams = "q=hello&d%75p=bar";
-    final byte[] postBytes = postParams.getBytes("UTF-8");
+    final byte[] postBytes = postParams.getBytes("US-ASCII");
     
     // Set up the expected behavior
     final String[] ct = new String[] {
@@ -224,7 +254,7 @@ public class SolrRequestParserTest exten
     expect(request.getContentLength()).andReturn(-1).anyTimes();
     expect(request.getQueryString()).andReturn(null).anyTimes();
     expect(request.getInputStream()).andReturn(new ServletInputStream() {
-      private final ByteArrayInputStream in = new ByteArrayInputStream(large.toString().getBytes("UTF-8"));
+      private final ByteArrayInputStream in = new ByteArrayInputStream(large.toString().getBytes("US-ASCII"));
       @Override public int read() { return in.read(); }
     });
     replay(request);

Modified: lucene/dev/branches/lucene4547/solr/example/solr/collection1/conf/solrconfig.xml
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/example/solr/collection1/conf/solrconfig.xml?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/example/solr/collection1/conf/solrconfig.xml (original)
+++ lucene/dev/branches/lucene4547/solr/example/solr/collection1/conf/solrconfig.xml Fri Jan 11 14:39:45 2013
@@ -1344,7 +1344,7 @@
 
        http://wiki.apache.org/solr/ClusteringComponent
 
-       You'll need to set the solr.cluster.enabled system property
+       You'll need to set the solr.clustering.enabled system property
        when running solr to run with clustering enabled:
 
             java -Dsolr.clustering.enabled=true -jar start.jar

Modified: lucene/dev/branches/lucene4547/solr/test-framework/src/java/org/apache/solr/cloud/AbstractZkTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/test-framework/src/java/org/apache/solr/cloud/AbstractZkTestCase.java?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/test-framework/src/java/org/apache/solr/cloud/AbstractZkTestCase.java (original)
+++ lucene/dev/branches/lucene4547/solr/test-framework/src/java/org/apache/solr/cloud/AbstractZkTestCase.java Fri Jan 11 14:39:45 2013
@@ -84,7 +84,7 @@ public abstract class AbstractZkTestCase
   }
   
   // static to share with distrib test
-  static void buildZooKeeper(String zkHost, String zkAddress, File solrhome, String config,
+  public static void buildZooKeeper(String zkHost, String zkAddress, File solrhome, String config,
       String schema) throws Exception {
     SolrZkClient zkClient = new SolrZkClient(zkHost, AbstractZkTestCase.TIMEOUT);
     zkClient.makePath("/solr", false, true);

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/admin.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/admin.html?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/admin.html (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/admin.html Fri Jan 11 14:39:45 2013
@@ -1,3 +1,4 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
 <html>
 
 <!--

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/css/styles/dataimport.css
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/css/styles/dataimport.css?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/css/styles/dataimport.css (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/css/styles/dataimport.css Fri Jan 11 14:39:45 2013
@@ -29,7 +29,7 @@
 
 #content #dataimport #form #navigation .current a
 {
-  background-image: url( ../../img/ico/document-import.png );
+  background-image: url( ../../img/ico/status.png );
 }
 
 #content #dataimport #form form
@@ -60,27 +60,41 @@
   width: 100%;
 }
 
+#content #dataimport #form input
+{
+  width: 98%;
+}
+
 #content #dataimport #form button
 {
   margin-top: 10px;
 }
 
-#content #dataimport #form button.loader
+#content #dataimport #form .execute span
 {
-  background-position: 2px 50%;
-  padding-left: 23px;
+  background-image: url( ../../img/ico/document-import.png );
+}
+
+#content #dataimport #form .refresh-status span
+{
+  background-image: url( ../../img/ico/arrow-circle.png );
+}
+
+#content #dataimport #form .refresh-status span.success
+{
+  background-image: url( ../../img/ico/tick.png );
 }
 
 #content #dataimport #form #start
 {
   float: left;
-  margin-right: 2%;
-  width: 49%;
+  width: 47%;
 }
 
 #content #dataimport #form #rows
 {
-  width: 49%;
+  float: right;
+  width: 47%;
 }
 
 #content #dataimport #form .checkbox input
@@ -89,9 +103,33 @@
   width: auto;
 }
 
+#content #dataimport #form #auto-refresh-status
+{
+  margin-top: 20px;
+}
+
+#content #dataimport #form #auto-refresh-status a
+{
+  background-image: url( ../../img/ico/ui-check-box-uncheck.png );
+  background-position: 0 50%;
+  color: #c0c0c0;
+  display: block;
+  padding-left: 21px;
+}
+
+#content #dataimport #form #auto-refresh-status a.on,
+#content #dataimport #form #auto-refresh-status a:hover
+{
+  color: #333;
+}
+
+#content #dataimport #form #auto-refresh-status a.on
+{
+  background-image: url( ../../img/ico/ui-check-box.png );
+}
+
 #content #dataimport #current_state
 {
-  display: none;
   padding: 10px;
   margin-bottom: 20px;
 }
@@ -117,6 +155,30 @@
 #content #dataimport #current_state .info
 {
   background-position: 0 1px;
+  position: relative;
+}
+
+#content #dataimport #current_state .info .details span
+{
+  color: #c0c0c0;
+}
+
+#content #dataimport #current_state .info .abort-import
+{
+  display: none;
+  position: absolute;
+  right: 0px;
+  top: 0px;
+}
+
+#content #dataimport #current_state .info .abort-import span
+{
+  background-image: url( ../../img/ico/cross.png );
+}
+
+#content #dataimport #current_state .info .abort-import.success span
+{
+  background-image: url( ../../img/ico/tick.png );
 }
 
 #content #dataimport #current_state.indexing
@@ -124,6 +186,16 @@
   background-color: #f9f9f9;
 }
 
+#content #dataimport #current_state.indexing .info
+{
+  background-image: url( ../../img/ico/hourglass.png );
+}
+
+#content #dataimport #current_state.indexing .info .abort-import
+{
+  display: block;
+}
+
 #content #dataimport #current_state.success
 {
   background-color: #e6f3e6;
@@ -139,6 +211,21 @@
   color: #080;
 }
 
+#content #dataimport #current_state.aborted
+{
+  background-color: #f3e6e6;
+}
+
+#content #dataimport #current_state.aborted .info
+{
+  background-image: url( ../../img/ico/slash.png );
+}
+
+#content #dataimport #current_state.aborted .info strong
+{
+  color: #800;
+}
+
 #content #dataimport #current_state.failure
 {
   background-color: #f3e6e6;
@@ -146,7 +233,7 @@
 
 #content #dataimport #current_state.failure .info
 {
-  background-image: url( ../../img/ico/slash.png );
+  background-image: url( ../../img/ico/cross-button.png );
 }
 
 #content #dataimport #current_state.failure .info strong
@@ -154,7 +241,17 @@
   color: #800;
 }
 
-#content #dataimport #config-error
+#content #dataimport #current_state.idle
+{
+  background-color: #e6e6ff;
+}
+
+#content #dataimport #current_state.idle .info
+{
+  background-image: url( ../../img/ico/information.png );
+}
+
+#content #dataimport #error
 {
   background-color: #f00;
   background-image: url( ../../img/ico/construction.png );
@@ -167,37 +264,43 @@
   padding-left: 35px;
 }
 
-#content #dataimport #config h2
+#content #dataimport .block h2
 {
   border-color: #c0c0c0;
   padding-left: 5px;
   position: relative;
 }
 
-#content #dataimport #config.hidden h2
+#content #dataimport .block.hidden h2
 {
   border-color: #fafafa;
 }
 
-#content #dataimport #config h2 a.toggle
+#content #dataimport .block h2 a.toggle
 {
   background-image: url( ../../img/ico/toggle-small.png );
   background-position: 0 50%;
   padding-left: 21px;
 }
 
-#content #dataimport #config.hidden h2 a.toggle
+#content #dataimport .block.hidden h2 a.toggle
 {
   background-image: url( ../../img/ico/toggle-small-expand.png );
 }
 
+#content #dataimport #config h2 a.r
+{
+  background-position: 3px 50%;
+  display: block;
+  float: right;
+  margin-left: 10px;
+  padding-left: 24px;
+  padding-right: 3px;
+}
+
 #content #dataimport #config h2 a.reload_config
 {
   background-image: url( ../../img/ico/arrow-circle.png );
-  padding-left: 21px;
-  position: absolute;
-  right: 5px;
-  top: 5px;
 }
 
 #content #dataimport #config h2 a.reload_config.success
@@ -210,13 +313,72 @@
   background-image: url( ../../img/ico/slash.png );
 }
 
-#content #dataimport #config.hidden .content
+#content #dataimport #config h2 a.debug_mode
+{
+  background-image: url( ../../img/ico/hammer.png );
+  color: #c0c0c0;
+}
+
+#content #dataimport #config.debug_mode h2 a.debug_mode
+{
+  background-color: #ff0;
+  background-image: url( ../../img/ico/hammer-screwdriver.png );
+  color: #333;
+}
+
+#content #dataimport .block.hidden .content
 {
   display: none;
 }
 
+#content #dataimport #config .content
+{
+  padding: 5px 2px;
+}
+
 #content #dataimport #dataimport_config .loader
 {
   background-position: 0 50%;
   padding-left: 21px;
+}
+
+#content #dataimport #dataimport_config .formatted
+{
+  border: 1px solid #fff;
+  display: block;
+  padding: 2px;
+}
+
+#content #dataimport .debug_mode #dataimport_config .formatted
+{
+  display: none;
+}
+
+#content #dataimport #dataimport_config .editable
+{
+  display: none;
+}
+
+#content #dataimport .debug_mode #dataimport_config .editable
+{
+  display: block;
+}
+
+#content #dataimport #dataimport_config .editable textarea
+{
+  font-family: monospace;
+  height: 120px;
+  min-height: 60px;
+  width: 100%;
+}
+
+#content #dataimport #debug_response
+{
+  display: none;
+}
+
+#content #dataimport #debug_response em
+{
+  color: #c0c0c0;
+  font-style: normal;
 }
\ No newline at end of file

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/js/lib/console.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/js/lib/console.js?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/js/lib/console.js (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/js/lib/console.js Fri Jan 11 14:39:45 2013
@@ -15,13 +15,15 @@
  limitations under the License.
 */
 
-if( 'undefined' === typeof( console ) )
+window.console = window.console || {};
+
+var names = ["log", "debug", "info", "warn", "error",
+    "assert", "dir", "dirxml", "group", "groupEnd", "time",
+    "timeEnd", "count", "trace", "profile", "profileEnd"];
+
+var i = 0;
+var l = names.length;
+for( i = 0; i < l; i++ )
 {
-  var console = {
-    log : function() {},
-    debug : function() {},
-    dump : function() {},
-    error : function() {},
-    warn : function(){}
-  };
-}
\ No newline at end of file
+  window.console[names[i]] = window.console[names[i]] || function() {};
+}

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/js/main.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/js/main.js?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/js/main.js (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/js/main.js Fri Jan 11 14:39:45 2013
@@ -20,6 +20,7 @@ require
   [
     'lib/order!lib/console',
     'lib/order!jquery',
+    'lib/order!lib/jquery.autogrow',
     'lib/order!lib/jquery.cookie',
     'lib/order!lib/jquery.form',
     'lib/order!lib/jquery.jstree',

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/app.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/app.js?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/app.js (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/app.js Fri Jan 11 14:39:45 2013
@@ -82,11 +82,7 @@ var sammy = $.sammy
       {},
       function( context )
       {
-        if( app.timeout )
-        {
-          console.debug( 'Clearing Timeout #' + app.timeout );
-          clearTimeout( app.timeout );
-        }
+        app.clear_timeout();
 
         var menu_wrapper = $( '#menu-wrapper' );
 
@@ -131,7 +127,7 @@ var sammy = $.sammy
 
 var solr_admin = function( app_config )
 {
-  self = this,
+  that = this,
 
   menu_element = null,
 
@@ -196,13 +192,13 @@ var solr_admin = function( app_config )
 
   this.set_cores_data = function set_cores_data( cores )
   {
-    self.cores_data = sort_cores_data( cores.status );
+    that.cores_data = sort_cores_data( cores.status );
     
-    self.menu_element
+    that.menu_element
       .empty();
 
     var core_count = 0;
-    for( var core_name in self.cores_data )
+    for( var core_name in that.cores_data )
     {
       core_count++;
       var core_path = config.solr_path + '/' + core_name;
@@ -240,7 +236,7 @@ var solr_admin = function( app_config )
                    + '    </ul>' + "\n"
                    + '</li>';
 
-      self.menu_element
+      that.menu_element
         .append( core_tpl );
     }
 
@@ -290,7 +286,7 @@ var solr_admin = function( app_config )
         },
         success : function( response )
         {
-          self.set_cores_data( response );
+          that.set_cores_data( response );
 
           for( var core_name in response.status )
           {
@@ -312,7 +308,7 @@ var solr_admin = function( app_config )
               },
               success : function( response )
               {
-                self.dashboard_values = response;
+                that.dashboard_values = response;
 
                 var environment_args = null;
                 var cloud_args = null;
@@ -399,7 +395,78 @@ var solr_admin = function( app_config )
         }
       }
     );
-  }
+  };
+
+  this.convert_duration_to_seconds = function convert_duration_to_seconds( str )
+  {
+    var seconds = 0;
+    var arr = new String( str || '' ).split( '.' );
+    var parts = arr[0].split( ':' ).reverse();
+    var parts_count = parts.length;
+
+    for( var i = 0; i < parts_count; i++ )
+    {
+      seconds += ( parseInt( parts[i], 10 ) || 0 ) * Math.pow( 60, i );
+    }
+
+    // treat more or equal than .5 as additional second
+    if( arr[1] && 5 <= parseInt( arr[1][0], 10 ) )
+    {
+      seconds++;
+    }
+
+    return seconds;
+  };
+
+  this.convert_seconds_to_readable_time = function convert_seconds_to_readable_time( seconds )
+  {
+    seconds = parseInt( seconds || 0, 10 );
+    var minutes = Math.floor( seconds / 60 );
+    var hours = Math.floor( minutes / 60 );
+
+    var text = [];
+    if( 0 !== hours )
+    {
+      text.push( hours + 'h' );
+      seconds -= hours * 60 * 60;
+      minutes -= hours * 60;
+    }
+
+    if( 0 !== minutes )
+    {
+      text.push( minutes + 'm' );
+      seconds -= minutes * 60;
+    }
+
+    if( 0 !== seconds )
+    {
+      text.push( ( '0' + seconds ).substr( -2 ) + 's' );
+    }
+
+    return text.join( ' ' );
+  };
+
+  this.clear_timeout = function clear_timeout()
+  {
+    if( !app.timeout )
+    {
+      return false;
+    }
+
+    console.debug( 'Clearing Timeout #' + this.timeout );
+    clearTimeout( this.timeout );
+    this.timeout = null;
+  };
+
+  this.format_json = function format_json( json_str )
+  {
+    if( JSON.stringify && JSON.parse )
+    {
+      json_str = JSON.stringify( JSON.parse( json_str ), undefined, 2 );
+    }
+
+    return json_str;
+  };
 
 };
 

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/cloud.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/cloud.js?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/cloud.js (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/cloud.js Fri Jan 11 14:39:45 2013
@@ -436,7 +436,7 @@ var prepare_graph = function( graph_elem
                   var shard = {
                     name: s,
                     data: {
-                      type : 'shard',
+                      type : 'shard'
                     },
                     children: nodes
                   };
@@ -446,7 +446,7 @@ var prepare_graph = function( graph_elem
                 var collection = {
                   name: c,
                   data: {
-                    type : 'collection',
+                    type : 'collection'
                   },
                   children: shards
                 };

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/dataimport.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/dataimport.js?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/dataimport.js (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/dataimport.js Fri Jan 11 14:39:45 2013
@@ -15,48 +15,8 @@
  limitations under the License.
 */
 
-var convert_duration_to_seconds = function( str )
-{
-  var ret = 0;
-  var parts = new String( str ).split( '.' ).shift().split( ':' ).reverse();
-  var parts_count = parts.length;
-    
-  for( var i = 0; i < parts_count; i++ )
-  {
-    ret += parseInt( parts[i], 10 ) * Math.pow( 60, i );
-  }
-
-  return ret;
-}
-
-var convert_seconds_to_readable_time = function( value )
-{
-  var text = [];
-  value = parseInt( value );
-
-  var minutes = Math.floor( value / 60 );
-  var hours = Math.floor( minutes / 60 );
-
-  if( 0 !== hours )
-  {
-    text.push( hours + 'h' );
-    value -= hours * 60 * 60;
-    minutes -= hours * 60;
-  }
-
-  if( 0 !== minutes )
-  {
-    text.push( minutes + 'm' );
-    value -= minutes * 60;
-  }
-
-  if( 0 !== value )
-  {
-    text.push( value + 's' );
-  }
-
-  return text.join( ' ' );
-}
+var dataimport_timeout = 2000;
+var cookie_dataimport_autorefresh = 'dataimport_autorefresh';
 
 sammy.bind
 (
@@ -152,7 +112,11 @@ sammy.get
         var dataimport_element = $( '#dataimport', content_element );
         var form_element = $( '#form', dataimport_element );
         var config_element = $( '#config', dataimport_element );
-        var config_error_element = $( '#config-error', dataimport_element );
+        var error_element = $( '#error', dataimport_element );
+        var debug_response_element = $( '#debug_response', dataimport_element );
+
+        var autorefresh_status = false;
+        var debug_mode = false;
 
         // handler
 
@@ -195,24 +159,23 @@ sammy.get
           $.ajax
           (
             {
-              url : handler_url + '?command=show-config',
+              url : handler_url + '?command=show-config&indent=true',
               dataType : 'xml',
               context : $( '#dataimport_config', config_element ),
               beforeSend : function( xhr, settings )
               {
+                error_element
+                  .empty()
+                  .hide();
               },
               success : function( config, text_status, xhr )
               {
                 dataimport_element
                   .removeClass( 'error' );
-                                    
-                config_error_element
-                  .hide();
 
                 config_element
                   .addClass( 'hidden' );
 
-
                 var entities = [ '<option value=""></option>' ];
 
                 $( 'document > entity', config )
@@ -226,6 +189,9 @@ sammy.get
                                 
                 $( '#entity', form_element )
                   .html( entities.join( "\n" ) );
+
+                $( '.editable textarea', this )
+                  .val( xhr.responseText.replace( /\n+$/, '' ) );
               },
               error : function( xhr, text_status, error_thrown )
               {
@@ -234,7 +200,8 @@ sammy.get
                   dataimport_element
                     .addClass( 'error' );
                                     
-                  config_error_element
+                  error_element
+                    .text( 'Dataimport XML-Configuration is not valid' )
                     .show();
 
                   config_element
@@ -248,7 +215,7 @@ sammy.get
                   xhr.responseText.esc() +
                   '</code></pre>'
                 );
-                this.html( code );
+                $( '.formatted', this ).html( code );
 
                 if( 'success' === text_status )
                 {
@@ -260,7 +227,7 @@ sammy.get
         }
         dataimport_fetch_config();
 
-        $( '.toggle', config_element )
+        $( '.block .toggle', dataimport_element )
           .die( 'click' )
           .live
           (
@@ -325,160 +292,339 @@ sammy.get
               );
               return false;
             }
-          )
+          );
+
+        var debug_mode_element = $( '.debug_mode', config_element );
+        debug_mode_element
+          .die( 'click' )
+          .live
+          (
+            'click',
+            function( event )
+            {
+              var self = $( this );
+              var block = self.closest( '.block' )
+
+              var debug_checkbox = $( 'input[name="debug"]', form_element );
+              var submit_span = $( 'button[type="submit"] span', form_element );
+
+              debug_mode = !debug_mode;
+
+              block.toggleClass( 'debug_mode', debug_mode );
+
+              if( debug_mode )
+              {
+                block.removeClass( 'hidden' );
+
+                debug_checkbox
+                  .attr( 'checked', 'checked' )
+                  .trigger( 'change' );
+                  
+                submit_span
+                  .data( 'original', submit_span.text() )
+                  .text( submit_span.data( 'debugmode' ) );
+
+                $( 'textarea', block )
+                  .autogrow()
+              }
+              else
+              {
+                submit_span
+                  .text( submit_span.data( 'original' ) )
+                  .removeData( 'original' );
+              }
+            }
+          );
+
+        // abort
+
+        var abort_import_element = $( '.abort-import', dataimport_element );
+        abort_import_element
+          .off( 'click' )
+          .on
+          (
+            'click',
+            function( event )
+            {
+              var span_element = $( 'span', this );
+
+              $.ajax
+              (
+                {
+                  url : handler_url + '?command=abort&wt=json',
+                  dataType : 'json',
+                  type: 'POST',
+                  context: $( this ),
+                  beforeSend : function( xhr, settings )
+                  {
+                    span_element
+                      .addClass( 'loader' );
+                  },
+                  success : function( response, text_status, xhr )
+                  {
+                    span_element
+                      .data( 'original', span_element.text() )
+                      .text( span_element.data( 'aborting' ) );
+
+                    this
+                      .removeClass( 'warn' )
+                      .addClass( 'success' );
+
+                    window.setTimeout
+                    (
+                      function()
+                      {
+                        $( 'span', abort_import_element )
+                          .removeClass( 'loader' )
+                          .text( span_element.data( 'original' ) )
+                          .removeData( 'original' );
+
+                        abort_import_element
+                          .removeClass( 'success' )
+                          .addClass( 'warn' );
+                      },
+                      dataimport_timeout * 2
+                    );
+
+                    dataimport_fetch_status();
+                  }
+                }
+              );
+              return false;
+            }
+          );
 
         // state
+
+        var status_button = $( 'form button.refresh-status', form_element );
+
+        status_button
+          .off( 'click' )
+          .on
+          (
+            'click',
+            function( event )
+            {
+              dataimport_fetch_status();
+              return false;
+            }
+          )
+          .trigger( 'click' );
                 
-        function dataimport_fetch_status()
+        function dataimport_fetch_status( clear_timeout )
         {
+          if( clear_timeout )
+          {
+            app.clear_timeout();
+          }
+
           $.ajax
           (
             {
-              url : handler_url + '?command=status',
-              dataType : 'xml',
+              url : handler_url + '?command=status&indent=true&wt=json',
+              dataType : 'json',
               beforeSend : function( xhr, settings )
               {
+                $( 'span', status_button )
+                  .addClass( 'loader' );
               },
               success : function( response, text_status, xhr )
               {
                 var state_element = $( '#current_state', content_element );
+                var time_element = $( '.time', state_element );
+
+                var status = response.status;
+                var rollback_time = response.statusMessages.Rolledback || null;
+                var abort_time = response.statusMessages.Aborted || null;
+                
+                var messages = response.statusMessages;
+                var messages_count = 0;
+                for( var key in messages ) { messages_count++; }
+
+                var format_number = function format_number( number )
+                {
+                  return ( number || 0 ).toString().replace( /\B(?=(\d{3})+(?!\d))/g, '\'' );
+                };
+
+                function dataimport_compute_details( response, details_element, elapsed_seconds )
+                {
+                  var config = {
+                    'Requests' : 'Total Requests made to DataSource',
+                    'Fetched' : 'Total Rows Fetched',
+                    'Skipped' : 'Total Documents Skipped',
+                    'Processed' : 'Total Documents Processed'
+                  };
+
+                  var details = [];
+                  for( var key in config )
+                  {
+                    var value = parseInt( response.statusMessages[config[key]], 10 );
 
-                var status = $( 'str[name="status"]', response ).text();
-                var rollback_element = $( 'str[name="Rolledback"]', response );
-                var messages_count = $( 'lst[name="statusMessages"] str', response ).size();
+                    var detail = '<abbr title="' + config[key].esc() + '">' + key.esc() + '</abbr>: ' +  format_number( value ).esc();
+                    if( elapsed_seconds && 'skipped' !== key.toLowerCase() )
+                    {
+                      detail += ' <span>(' + format_number( Math.round( value / elapsed_seconds ) ).esc() + '/s)</span>'
+                    }
+
+                    details.push( detail );
+                  };
+
+                  details_element
+                    .html( details.join( ', ' ) )
+                    .show();
+                };
 
-                var started_at = $( 'str[name="Full Dump Started"]', response ).text();
-                if( !started_at )
+                var get_time_taken = function get_default_time_taken()
                 {
-                  started_at = (new Date()).toGMTString();
-                }
+                  var time_taken_text = response.statusMessages['Time taken'];
+                  return app.convert_duration_to_seconds( time_taken_text );
+                };
 
-                function dataimport_compute_details( response, details_element )
+                var get_default_info_text = function default_info_text()
                 {
-                  var details = [];
-                                    
-                  var requests = parseInt( $( 'str[name="Total Requests made to DataSource"]', response ).text(), 10 );
-                  if( requests )
-                  {
-                    details.push
-                    (
-                      '<abbr title="Total Requests made to DataSource">Requests</abbr>: ' +
-                      requests
-                    );
-                  }
+                  var info_text = response.statusMessages[''] || '';
 
-                  var fetched = parseInt( $( 'str[name="Total Rows Fetched"]', response ).text(), 10 );
-                  if( fetched )
-                  {
-                    details.push
-                    (
-                      '<abbr title="Total Rows Fetched">Fetched</abbr>: ' +
-                      fetched
-                    );
-                  }
+                  // format numbers included in status nicely
+                  info_text = info_text.replace
+                  (
+                    /\d{4,}/g,
+                    function( match, position, string )
+                    {
+                      return format_number( parseInt( match, 10 ) );
+                    }
+                  );
 
-                  var skipped = parseInt( $( 'str[name="Total Documents Skipped"]', response ).text(), 10 );
-                  if( requests )
+                  var time_taken_text = app.convert_seconds_to_readable_time( get_time_taken() );
+                  if( time_taken_text )
                   {
-                    details.push
-                    (
-                      '<abbr title="Total Documents Skipped">Skipped</abbr>: ' +
-                      skipped
-                    );
+                    info_text += ' (Duration: ' + time_taken_text.esc() + ')';
                   }
 
-                  var processed = parseInt( $( 'str[name="Total Documents Processed"]', response ).text(), 10 );
-                  if( processed )
-                  {
-                    details.push
-                    (
-                      '<abbr title="Total Documents Processed">Processed</abbr>: ' +
-                      processed
-                    );
-                  }
+                  return info_text;
+                };
 
-                  details_element
-                    .html( details.join( ', ' ) )
+                var show_info = function show_info( info_text, elapsed_seconds )
+                {
+                  $( '.info strong', state_element )
+                    .text( info_text || get_default_info_text() );
+
+                  $( '.info .details', state_element )
+                    .hide();
+                };
+
+                var show_full_info = function show_full_info( info_text, elapsed_seconds )
+                {
+                  show_info( info_text, elapsed_seconds );
+
+                  dataimport_compute_details
+                  (
+                    response,
+                    $( '.info .details', state_element ),
+                    elapsed_seconds || get_time_taken()
+                  );
+                };
+
+                var set_time = function set_time( time_text )
+                {
+                  time_element
+                    .text( time_text )
+                    .removeData( 'timeago' )
+                    .timeago()
                     .show();
                 }
 
                 state_element
-                  .removeClass( 'indexing' )
-                  .removeClass( 'success' )
-                  .removeClass( 'failure' );
+                  .removeAttr( 'class' );
+
+                 time_element
+                    .empty()
+                    .hide();
                                 
                 $( '.info', state_element )
                   .removeClass( 'loader' );
 
-                if( 0 !== rollback_element.size() )
+                if( 'busy' === status )
                 {
                   state_element
-                    .addClass( 'failure' )
-                    .show();
+                    .addClass( 'indexing' );
 
-                  $( '.time', state_element )
-                    .text( rollback_element.text() )
-                    .timeago()
-                    .show();
+                  if( autorefresh_status )
+                  {
+                    $( '.info', state_element )
+                      .addClass( 'loader' );
+                  }
 
-                  $( '.info strong', state_element )
-                    .text( $( 'str[name=""]', response ).text() );
+                  var time_elapsed_text = response.statusMessages['Time Elapsed'];
+                  var elapsed_seconds = app.convert_duration_to_seconds( time_elapsed_text );
+                  time_elapsed_text = app.convert_seconds_to_readable_time( elapsed_seconds );
 
-                  $( '.info .details', state_element )
-                    .hide();
-                                    
-                  console.debug( 'rollback @ ', rollback_element.text() );
+                  var info_text = time_elapsed_text
+                                ? 'Indexing since ' + time_elapsed_text
+                                : 'Indexing ...';
+
+                  show_full_info( info_text, elapsed_seconds );
+
+                  if( !app.timeout && autorefresh_status )
+                  {
+                    app.timeout = window.setTimeout
+                    (
+                      function()
+                      {
+                        dataimport_fetch_status( true )
+                      },
+                      dataimport_timeout
+                    );
+                  }
                 }
-                else if( 'idle' === status && 0 !== messages_count )
+                else if( rollback_time )
                 {
                   state_element
-                    .addClass( 'success' )
-                    .show();
+                    .addClass( 'failure' );
 
-                  $( '.time', state_element )
-                    .text( started_at )
-                    .timeago()
-                    .show();
+                  set_time( rollback_time );
 
-                  $( '.info strong', state_element )
-                    .text( $( 'str[name=""]', response ).text() );
-
-                  dataimport_compute_details( response, $( '.info .details', state_element ) );
+                  show_full_info();
                 }
-                else if( 'busy' === status )
+                else if( abort_time )
                 {
                   state_element
-                    .addClass( 'indexing' )
-                    .show();
-
-                  $( '.time', state_element )
-                    .text( started_at )
-                    .timeago()
-                    .show();
+                    .addClass( 'aborted' );
 
-                  $( '.info', state_element )
-                    .addClass( 'loader' );
+                  set_time( abort_time );
 
-                  var indexing_text = 'Indexing ...';
+                  show_full_info( 'Aborting current Import ...' );
+                }
+                else if( 'idle' === status && 0 !== messages_count )
+                {
+                  state_element
+                    .addClass( 'success' );
 
-                  var time_elapsed_text = $( 'str[name="Time Elapsed"]', response ).text();
-                  time_elapsed_text = convert_seconds_to_readable_time( convert_duration_to_seconds( time_elapsed_text ) );
-                  if( time_elapsed_text.length )
+                  var started_at = response.statusMessages['Full Dump Started'];
+                  if( started_at )
                   {
-                    indexing_text = 'Indexing since ' + time_elapsed_text
+                    set_time( started_at );
                   }
 
-                  $( '.info strong', state_element )
-                    .text( indexing_text );
-                                    
-                  dataimport_compute_details( response, $( '.info .details', state_element ) );
-
-                  window.setTimeout( dataimport_fetch_status, 2000 );
+                  show_full_info();
                 }
-                else
+                else 
                 {
-                  state_element.hide();
+                  state_element
+                    .addClass( 'idle' );
+
+                  show_info( 'No information available (idle)' );
                 }
+
+                // show raw status
+
+                var code = $(
+                  '<pre class="syntax language-json"><code>' +
+                  app.format_json( xhr.responseText ).esc() +
+                  '</code></pre>'
+                );
+
+                $( '#raw_output_container', content_element ).html( code );
+                hljs.highlightBlock( code.get(0) );
               },
               error : function( xhr, text_status, error_thrown )
               {
@@ -489,24 +635,47 @@ sammy.get
               },
               complete : function( xhr, text_status )
               {
+                $( 'span', status_button )
+                  .removeClass( 'loader' )
+                  .addClass( 'success' );
+
+                window.setTimeout
+                (
+                  function()
+                  {
+                    $( 'span', status_button )
+                      .removeClass( 'success' );
+                  },
+                  dataimport_timeout / 2
+                );
               }
             }
           );
         }
-        dataimport_fetch_status();
 
         // form
 
-        $( 'form', form_element )
+        var form = $( 'form', form_element );
+
+        form
           .ajaxForm
           (
             {
               url : handler_url,
-              dataType : 'xml',
+              data : {
+                wt : 'json',
+                indent : 'true'
+              },
+              dataType : 'json',
+              type: 'POST',
               beforeSend : function( xhr, settings )
               {
-                $( 'form button', form_element )
+                $( 'button[type="submit"] span', form_element )
                   .addClass( 'loader' );
+
+                error_element
+                  .empty()
+                  .hide();
               },
               beforeSubmit : function( array, form, options )
               {
@@ -545,22 +714,91 @@ sammy.get
                     array.push( { name : tmp[0], value: tmp[1] } );
                   }
                 }
+
+                if( debug_mode )
+                {
+                  array.push( { name: 'dataConfig', value: $( '#dataimport_config .editable textarea' ).val() } );
+                }
               },
               success : function( response, text_status, xhr )
               {
-                dataimport_fetch_status();
               },
               error : function( xhr, text_status, error_thrown )
               {
-                console.debug( arguments );
+                var response = null;
+                try
+                {
+                  eval( 'response = ' + xhr.responseText + ';' );
+                }
+                catch( e ){}
+
+                error_element
+                  .text( response.error.msg || 'Unknown Error (Exception w/o Message)' )
+                  .show();
               },
               complete : function( xhr, text_status )
               {
-                $( 'form button', form_element )
+                $( 'button[type="submit"] span', form_element )
                   .removeClass( 'loader' );
+
+                var debug = $( 'input[name="debug"]:checked', form );
+                if( 0 !== debug.size() )
+                {
+                  var code = $(
+                    '<pre class="syntax language-json"><code>' +
+                    app.format_json( xhr.responseText ).esc() +
+                    '</code></pre>'
+                  );
+
+                  $( '.content', debug_response_element ).html( code );
+                  hljs.highlightBlock( code.get(0) );
+                }
+
+                dataimport_fetch_status();
               }
             }
           );
+
+        $( 'input[name="debug"]', form )
+          .off( 'change' )
+          .on
+          (
+            'change',
+            function( event )
+            {
+              debug_response_element.toggle( this.checked );
+            }
+          );
+
+        $( '#auto-refresh-status a', form_element )
+          .off( 'click' )
+          .on
+          (
+            'click',
+            function( event )
+            {
+              $.cookie( cookie_dataimport_autorefresh, $.cookie( cookie_dataimport_autorefresh ) ? null : true );
+              $( this ).trigger( 'state' );
+
+              dataimport_fetch_status();
+
+              return false;
+            }
+          )
+          .off( 'state' )
+          .on
+          (
+            'state',
+            function( event )
+            {
+              autorefresh_status = !!$.cookie( cookie_dataimport_autorefresh );
+
+              $.cookie( cookie_dataimport_autorefresh )
+                ? $( this ).addClass( 'on' )
+                : $( this ).removeClass( 'on' );
+            }
+          )
+          .trigger( 'state' );
       }
     );
   }

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/index.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/index.js?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/index.js (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/index.js Fri Jan 11 14:39:45 2013
@@ -42,7 +42,7 @@ var generate_bar = function( bar_contain
   if( bar_data['used'] )
   {
     bar_level++;
-    $( '.bar-used.bar', bar_holder ).width( new String( (bar_data['used']/bar_data['max'])*100 ) + '%' );
+    $( '.bar-used.bar', bar_holder ).width( new String( (bar_data['used']/bar_data['total'])*100 ) + '%' );
     $( '.bar-used.val', bar_holder ).text( bar_data['used'] );
   }
 

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/plugins.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/plugins.js?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/plugins.js (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/plugins.js Fri Jan 11 14:39:45 2013
@@ -287,7 +287,7 @@ var render_plugin_data = function( plugi
     var txt = $(this).html();
     if(txt.indexOf("http") >= 0) {
       $(this).linker({
-         className : 'linker',
+         className : 'linker'
       });
     }
   });
@@ -423,4 +423,4 @@ sammy.get
       }
     );
   }
-);
\ No newline at end of file
+);

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/query.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/query.js?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/query.js (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/query.js Fri Jan 11 14:39:45 2013
@@ -56,7 +56,7 @@ sammy.get
 
                 json : function( xhr )
                 {
-                  return JSON.stringify( JSON.parse( xhr.responseText ), undefined, 2 );
+                  return app.format_json( xhr.responseText );
                 }
 
               };

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/replication.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/replication.js?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/replication.js (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/js/scripts/replication.js Fri Jan 11 14:39:45 2013
@@ -22,49 +22,6 @@ var core_basepath = null;
 var navigation_element = null;
 var replication_element = null;
 
-var convert_duration_to_seconds = function( str )
-{
-  var ret = 0;
-  var parts = new String( str ).split( ':' ).reverse();
-  var parts_count = parts.length;
-    
-  for( var i = 0; i < parts_count; i++ )
-  {
-    ret += parseInt( parts[i], 10 ) * Math.pow( 60, i );
-  }
-
-  return ret;
-}
-
-var convert_seconds_to_readable_time = function( value )
-{
-  var text = [];
-  value = parseInt( value );
-
-  var minutes = Math.floor( value / 60 );
-  var hours = Math.floor( minutes / 60 );
-
-  if( 0 !== hours )
-  {
-    text.push( hours + 'h' );
-    value -= hours * 60 * 60;
-    minutes -= hours * 60;
-  }
-
-  if( 0 !== minutes )
-  {
-    text.push( minutes + 'm' );
-    value -= minutes * 60;
-  }
-
-  if( 0 !== value )
-  {
-    text.push( value + 's' );
-  }
-
-  return text.join( ' ' );
-}
-
 var init_timer = function( next_tick )
 {
   if( timer_timeout )
@@ -83,7 +40,7 @@ var update_timer = function( next_tick )
   }
 
   $( 'p .tick', timer_element )
-    .text( convert_seconds_to_readable_time( next_tick ) );
+    .text( app.convert_seconds_to_readable_time( next_tick ) );
 
   timer_timeout = window.setTimeout
   (
@@ -151,7 +108,7 @@ var replication_fetch_status = function(
 
           var eta_element = $( '#eta', progress_element );
           $( 'span', eta_element )
-            .text( convert_seconds_to_readable_time( data.slave.timeRemaining ) );
+            .text( app.convert_seconds_to_readable_time( data.slave.timeRemaining ) );
 
           var bar_element = $( '#bar', progress_element );
           $( '.files span', bar_element )
@@ -394,7 +351,7 @@ var replication_fetch_status = function(
               timer_element = $( '.timer', navigation_element );
               approx_element = $( '.approx', timer_element );
 
-              var next_tick = convert_duration_to_seconds( data.slave.pollInterval );
+              var next_tick = app.convert_duration_to_seconds( data.slave.pollInterval );
               approx_element.show();
 
               if( data.slave.nextExecutionAt )

Modified: lucene/dev/branches/lucene4547/solr/webapp/web/tpl/dataimport.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4547/solr/webapp/web/tpl/dataimport.html?rev=1432065&r1=1432064&r2=1432065&view=diff
==============================================================================
--- lucene/dev/branches/lucene4547/solr/webapp/web/tpl/dataimport.html (original)
+++ lucene/dev/branches/lucene4547/solr/webapp/web/tpl/dataimport.html Fri Jan 11 14:39:45 2013
@@ -18,27 +18,46 @@ limitations under the License.
 
   <div id="frame">
 
+    <div id="error"></div>
+
     <div id="current_state">
 
       <span class="time"></span>
       <div class="info">
+
         <strong></strong>
         <div class="details"></div>
+
+        <button class="abort-import warn"><span data-aborting="Aborting Import">Abort Import</span></button>
+
       </div>
     
     </div>
 
-    <div id="config-error">
+    <div class="block hidden" id="raw_output">
+
+      <h2>
+        <a class="toggle"><span>Raw Status-Output</span></a>
+      </h2>
+        
+      <div class="message-container">
+          <div class="message"></div>
+      </div>
+
+      <div class="content">
 
-      Dataimport XML-Configuration is not valid
+        <div id="raw_output_container"></div>
 
+      </div>
+    
     </div>
 
     <div class="block hidden" id="config">
 
-      <h2>
-        <a class="toggle"><span>Dataimport Configuration</span></a>
-        <a class="reload_config" title="Reload Configuration">Reload</a>
+      <h2 class="clearfix">
+        <a class="toggle"><span>Configuration</span></a>
+        <a class="r reload_config" title="Reload Configuration">Reload</a>
+        <a class="r debug_mode">Debug-Mode</a>
       </h2>
         
       <div class="message-container">
@@ -49,13 +68,41 @@ limitations under the License.
 
         <div id="dataimport_config">
 
-          <div class="loader">Loading ...</div>
-        
+          <div class="formatted">
+
+            <div class="loader">Loading ...</div>
+          
+          </div>
+
+          <div class="editable">
+
+            <textarea></textarea>
+          
+          </div>
+
         </div>
 
       </div>
     
     </div>
+
+    <div class="block hidden" id="debug_response">
+
+      <h2>
+        <a class="toggle"><span>Raw Debug-Response</span></a>
+      </h2>
+        
+      <div class="message-container">
+          <div class="message"></div>
+      </div>
+
+      <div class="content">
+
+        <em>No Request executed</em>
+
+      </div>
+    
+    </div>
   
   </div>
 
@@ -97,6 +144,11 @@ limitations under the License.
         <a rel="help">Optimize</a>
       </label>
 
+      <label for="debug" class="checkbox">
+        <input type="checkbox" name="debug" id="debug" value="true">
+        <a rel="help">Debug</a>
+      </label>
+
       <label for="entity">
         <a rel="help">Entity</a>
       </label>
@@ -106,17 +158,22 @@ limitations under the License.
         <a rel="help">Start</a>,
         <a rel="help">Rows</a>
       </label>
-      <input type="text" id="start" placeholder="0">
-      <input type="text" id="rows" placeholder="10">
+      <div class="clearfix">
+        <input type="text" id="start" placeholder="0">
+        <input type="text" id="rows" placeholder="10">
+      </div>
 
       <label for="custom_parameters">
         <a rel="help">Custom Parameters</a>
       </label>
       <input type="text" id="custom_parameters" value="" placeholder="key1=val1&amp;key2=val2">
 
-      <button type="submit">Execute Import</button>
+      <button class="execute" type="submit"><span data-debugmode="Execute with this Configuration →">Execute</span></button>
+      <button class="refresh-status"><span>Refresh Status</span></button>
     
     </form>
+
+    <p id="auto-refresh-status"><a>Auto-Refresh Status</a></p>
   
   </div>