Fix NPE when value of a group is null

- New configuration parameter ResponseParser.processGroupValueNull and
  ResponseParser.groupValueNull.
- Fix NPE in ResponseParser
- New grouping tests
- Rename SolrResponseParser_Test -> ResponseParser_Test
diff --git a/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/SolrConfig_Test.java b/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/SolrConfig_Test.java
index 6f9aebe..640c612 100755
--- a/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/SolrConfig_Test.java
+++ b/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/SolrConfig_Test.java
@@ -1,19 +1,21 @@
 /*********************************************************************************************************************

- * Copyright (c) 2008, 2015 Empolis Information Management GmbH and brox IT Solutions GmbH. All rights reserved.

- * This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 

- * which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html

-**********************************************************************************************************************/

+ * Copyright (c) 2008, 2015 Empolis Information Management GmbH and brox IT Solutions GmbH. All rights reserved. This

+ * program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which

+ * accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html

+ **********************************************************************************************************************/

 package org.eclipse.smila.solr;

 

-import junit.framework.TestCase;

-

 import org.apache.commons.lang.NullArgumentException;

 import org.eclipse.smila.datamodel.AnyMap;

 import org.eclipse.smila.datamodel.AnySeq;

 import org.eclipse.smila.datamodel.DataFactory;

 

+import junit.framework.TestCase;

+

 public class SolrConfig_Test extends TestCase {

 

+  private final DataFactory _factory = DataFactory.DEFAULT;

+

   private AnyMap getSampleConfig() {

     final AnyMap config = DataFactory.DEFAULT.createAnyMap();

     config.put("key", "value");

@@ -30,14 +32,14 @@
     assertEquals("seqValue", config.getSeq("seq").get(0).asValue().asString());

     assertEquals(SolrConfig.Mode.CLOUD.toString(), solrConfig.getMode().toString());

   }

-  

+

   public void test_SolrConfigModeException() {

     final SolrConfig solrConfig = new SolrConfig(getSampleConfig());

     final AnyMap config = solrConfig.getConfigMap();

     config.put("mode", "any");

     try {

       solrConfig.getMode();

-    } catch (Exception e) {

+    } catch (final Exception e) {

       if (e instanceof IllegalArgumentException) {

         return;

       }

@@ -85,7 +87,7 @@
     final SolrConfig solrConfig = new SolrConfig(getSampleConfig());

     try {

       solrConfig.getRestUri();

-    } catch (Exception e) {

+    } catch (final Exception e) {

       if (e instanceof NullArgumentException) {

         return;

       }

@@ -105,6 +107,30 @@
     assertFalse(solrConfig.isFetchFacetFieldType());

   }

 

+  public void test_isProcessGroupValueNull() {

+    final SolrConfig solrConfig = new SolrConfig(_factory.createAnyMap());

+    final AnyMap config = solrConfig.getConfigMap();

+    config.put(SolrConfig.PROCESS_GROUP_VALUE_NULL, true);

+    assertTrue(solrConfig.isProcessGroupValueNull());

+  }

+

+  public void test_isProcessGroupValueNullDefault() {

+    final SolrConfig solrConfig = new SolrConfig(_factory.createAnyMap());

+    assertFalse(solrConfig.isProcessGroupValueNull());

+  }

+

+  public void test_getGroupValueNull() {

+    final SolrConfig solrConfig = new SolrConfig(_factory.createAnyMap());

+    final AnyMap config = solrConfig.getConfigMap();

+    config.put(SolrConfig.GROUP_VALUE_NULL, "test");

+    assertEquals("test", solrConfig.getGroupValueNull());

+  }

+

+  public void test_getGroupValueNullDefault() {

+    final SolrConfig solrConfig = new SolrConfig(_factory.createAnyMap());

+    assertEquals("<null>", solrConfig.getGroupValueNull());

+  }

+

   public void test_getLoadBalancedSolrServerServerUrls() {

     final SolrConfig solrConfig = new SolrConfig(getSampleConfig());

     final AnyMap config = solrConfig.getConfigMap();

@@ -126,7 +152,7 @@
     final SolrConfig solrConfig = new SolrConfig(getSampleConfig());

     try {

       solrConfig.getLoadBalancedSolrServerServerUrls();

-    } catch (Exception e) {

+    } catch (final Exception e) {

       if (e instanceof NullArgumentException) {

         return;

       }

diff --git a/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/search/ResponseParser_Grouping_Test.java b/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/search/ResponseParser_Grouping_Test.java
new file mode 100644
index 0000000..db7a446
--- /dev/null
+++ b/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/search/ResponseParser_Grouping_Test.java
@@ -0,0 +1,188 @@
+/**
+ *
+ */
+package org.eclipse.smila.solr.search;
+
+import java.util.ArrayList;
+
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.SimpleOrderedMap;
+import org.eclipse.smila.datamodel.AnySeq;
+import org.eclipse.smila.datamodel.DataFactory;
+import org.eclipse.smila.datamodel.Record;
+import org.eclipse.smila.search.api.helper.ResultAccessor;
+import org.eclipse.smila.solr.SolrConfig;
+
+import junit.framework.TestCase;
+
+/**
+ * @author pwissel
+ *
+ */
+public class ResponseParser_Grouping_Test extends TestCase {
+
+  private final DataFactory _factory = DataFactory.DEFAULT;
+
+  private SolrConfig _config;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    _config = new SolrConfig(_factory.createAnyMap());
+  }
+
+  private NamedList<Object> prepareResponse(final ArrayList<Object> groups) {
+    // solr response
+    final NamedList<Object> response = new NamedList<>();
+    // grouped
+    final NamedList<Object> grouped = new NamedList<>();
+    response.add("grouped", grouped);
+    // field
+    final SimpleOrderedMap<Object> field = new SimpleOrderedMap<>();
+    grouped.add("field", field);
+    field.add("matches", new Integer(2));
+    // groups
+    field.add("groups", groups);
+    return response;
+  }
+
+  private ResultAccessor runParser(final NamedList<Object> res) {
+    final QueryResponse response = new QueryResponse(res, null);
+    final ResponseParser parser = new ResponseParser(_factory.createRecord(), _config, "index");
+    final Record result = parser.toRecord(response);
+    return new ResultAccessor(result);
+  }
+
+  public void test_Groups() {
+    // prepare config
+    ;
+    // prepare response
+    final NamedList<Object> response = prepareResponse(new ArrayList<Object>());
+    // run parser
+    final ResultAccessor accessor = runParser(response);
+    // check results
+    assertNotNull(accessor.getGroups());
+    assertEquals(2, accessor.getGroups().getLongValue("matches").intValue());
+    assertNotNull(accessor.getGroups().getSeq("field"));
+  }
+
+  public void test_OneGroup() {
+    // prepare config
+    ;
+    // prepare response
+    final ArrayList<Object> groups = new ArrayList<Object>();
+    final SimpleOrderedMap<Object> group1 = new SimpleOrderedMap<>();
+    groups.add(group1);
+    group1.add("groupValue", "group1");
+    group1.add("doclist", new SolrDocumentList());
+    final NamedList<Object> res = prepareResponse(groups);
+    // run parser
+    final ResultAccessor accessor = runParser(res);
+    // check results
+    final AnySeq seq = accessor.getGroups().getSeq("field");
+    assertEquals(1, seq.size());
+    assertNotNull(seq.getMap(0));
+    assertEquals("group1", seq.getMap(0).getStringValue("value"));
+    assertNotNull(seq.getMap(0).get("results"));
+  }
+
+  public void test_TwoGroups() {
+    // prepare config
+    ;
+    // prepare response
+    final ArrayList<Object> groups = new ArrayList<Object>();
+    final SimpleOrderedMap<Object> group1 = new SimpleOrderedMap<>();
+    groups.add(group1);
+    group1.add("groupValue", "group1");
+    group1.add("doclist", new SolrDocumentList());
+    final SimpleOrderedMap<Object> group2 = new SimpleOrderedMap<>();
+    groups.add(group2);
+    group2.add("groupValue", "group2");
+    group2.add("doclist", new SolrDocumentList());
+    final NamedList<Object> res = prepareResponse(groups);
+    // run parser
+    final ResultAccessor accessor = runParser(res);
+    // check results
+    final AnySeq seq = accessor.getGroups().getSeq("field");
+    assertEquals(2, seq.size());
+    assertNotNull(seq.getMap(1));
+    assertEquals("group2", seq.getMap(1).getStringValue("value"));
+    assertNotNull(seq.getMap(1).get("results"));
+  }
+
+  public void test_NotProcessNullValueGroup() {
+    // prepare config
+    ;
+    // prepare response
+    final ArrayList<Object> groups = new ArrayList<Object>();
+    final SimpleOrderedMap<Object> group1 = new SimpleOrderedMap<>();
+    groups.add(group1);
+    group1.add("groupValue", null);
+    group1.add("doclist", new SolrDocumentList());
+    final SimpleOrderedMap<Object> group2 = new SimpleOrderedMap<>();
+    groups.add(group2);
+    group2.add("groupValue", "group2");
+    group2.add("doclist", new SolrDocumentList());
+    final NamedList<Object> res = prepareResponse(groups);
+    // run parser
+    final ResultAccessor accessor = runParser(res);
+    // check results
+    final AnySeq seq = accessor.getGroups().getSeq("field");
+    assertEquals(1, seq.size());
+    assertNotNull(seq.getMap(0));
+    assertEquals("group2", seq.getMap(0).getStringValue("value"));
+    assertNotNull(seq.getMap(0).get("results"));
+  }
+
+  public void test_ProcessNullValueGroupDefault() {
+    // prepare config
+    _config.getConfigMap().put(SolrConfig.PROCESS_GROUP_VALUE_NULL, true);
+    // prepare response
+    final ArrayList<Object> groups = new ArrayList<Object>();
+    final SimpleOrderedMap<Object> group1 = new SimpleOrderedMap<>();
+    groups.add(group1);
+    group1.add("groupValue", null);
+    group1.add("doclist", new SolrDocumentList());
+    final SimpleOrderedMap<Object> group2 = new SimpleOrderedMap<>();
+    groups.add(group2);
+    group2.add("groupValue", "group2");
+    group2.add("doclist", new SolrDocumentList());
+    final NamedList<Object> res = prepareResponse(groups);
+    // run parser
+    final ResultAccessor accessor = runParser(res);
+    // check results
+    final AnySeq seq = accessor.getGroups().getSeq("field");
+    assertEquals(2, seq.size());
+    assertNotNull(seq.getMap(0));
+    assertEquals("<null>", seq.getMap(0).getStringValue("value"));
+    assertNotNull(seq.getMap(0).get("results"));
+  }
+
+  public void test_ProcessNullValueGroup() {
+    // prepare config
+    _config.getConfigMap().put(SolrConfig.PROCESS_GROUP_VALUE_NULL, true);
+    _config.getConfigMap().put(SolrConfig.GROUP_VALUE_NULL, "notnull");
+    // prepare response
+    final ArrayList<Object> groups = new ArrayList<Object>();
+    final SimpleOrderedMap<Object> group1 = new SimpleOrderedMap<>();
+    groups.add(group1);
+    group1.add("groupValue", null);
+    group1.add("doclist", new SolrDocumentList());
+    final SimpleOrderedMap<Object> group2 = new SimpleOrderedMap<>();
+    groups.add(group2);
+    group2.add("groupValue", "group2");
+    group2.add("doclist", new SolrDocumentList());
+    final NamedList<Object> res = prepareResponse(groups);
+    // run parser
+    final ResultAccessor accessor = runParser(res);
+    // check results
+    final AnySeq seq = accessor.getGroups().getSeq("field");
+    assertEquals(2, seq.size());
+    assertNotNull(seq.getMap(0));
+    assertEquals("notnull", seq.getMap(0).getStringValue("value"));
+    assertNotNull(seq.getMap(0).get("results"));
+  }
+
+}
diff --git a/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/search/SolrResponseParser_Test.java b/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/search/ResponseParser_Test.java
similarity index 91%
rename from core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/search/SolrResponseParser_Test.java
rename to core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/search/ResponseParser_Test.java
index 04b585e..2d78e73 100755
--- a/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/search/SolrResponseParser_Test.java
+++ b/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/search/ResponseParser_Test.java
@@ -1,15 +1,13 @@
 /*********************************************************************************************************************

- * Copyright (c) 2008, 2015 Empolis Information Management GmbH and brox IT Solutions GmbH. All rights reserved.

- * This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 

- * which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html

-**********************************************************************************************************************/

+ * Copyright (c) 2008, 2015 Empolis Information Management GmbH and brox IT Solutions GmbH. All rights reserved. This

+ * program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which

+ * accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html

+ **********************************************************************************************************************/

 package org.eclipse.smila.solr.search;

 

 import java.util.ArrayList;

 import java.util.List;

 

-import junit.framework.TestCase;

-

 import org.apache.solr.client.solrj.impl.CloudSolrServer;

 import org.apache.solr.client.solrj.response.QueryResponse;

 import org.apache.solr.client.solrj.response.SolrResponseBase;

@@ -27,7 +25,9 @@
 import org.eclipse.smila.solr.SolrConstants;

 import org.eclipse.smila.solr.params.SolrParams;

 

-public class SolrResponseParser_Test extends TestCase {

+import junit.framework.TestCase;

+

+public class ResponseParser_Test extends TestCase {

 

   private final String ID_FIELD = "_recordid";

 

@@ -53,9 +53,8 @@
     }

     final ResponseParser parser = new ResponseParser(_factory.createRecord(), getSolrConfig(), ID_FIELD);

     final Record result = parser.toRecord(solrResponse);

-    final AnyMap responseHeader =

-      result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE).getMap(ResponseAccessor.RESPONSE)

-        .getMap(SolrConstants.RESPONSE_HEADER);

+    final AnyMap responseHeader = result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE)

+      .getMap(ResponseAccessor.RESPONSE).getMap(SolrConstants.RESPONSE_HEADER);

     assertNotNull(responseHeader);

     assertEquals("val", responseHeader.getStringValue("key"));

     assertEquals("val2", responseHeader.getStringValue("key2"));

@@ -244,9 +243,8 @@
     final ResponseParser parser = new ResponseParser(_factory.createRecord(), getSolrConfig(), ID_FIELD);

     {

       final Record result = parser.toRecord(queryResponse);

-      final AnyMap terms =

-        result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE).getMap(ResponseAccessor.RESPONSE)

-          .getMap(SolrConstants.TERMS);

+      final AnyMap terms = result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE)

+        .getMap(ResponseAccessor.RESPONSE).getMap(SolrConstants.TERMS);

       assertNotNull(terms.get("fieldName1"));

       assertNotNull(terms.get("fieldName2"));

       assertEquals(23, terms.getMap("fieldName1").getLongValue("name1").intValue());

@@ -277,9 +275,8 @@
     final ResponseParser parser = new ResponseParser(_factory.createRecord(), getSolrConfig(), ID_FIELD);

     {

       final Record result = parser.toRecord(queryResponse);

-      final AnyMap suggestions =

-        result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE).getMap(ResponseAccessor.RESPONSE)

-          .getMap(SolrConstants.SPELLCHECK).getMap(SolrConstants.SUGGESTIONS);

+      final AnyMap suggestions = result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE)

+        .getMap(ResponseAccessor.RESPONSE).getMap(SolrConstants.SPELLCHECK).getMap(SolrConstants.SUGGESTIONS);

       assertNotNull(suggestions);

       final AnyMap olktimer = suggestions.getMap("Olktimer");

       assertNotNull(olktimer);

@@ -324,9 +321,8 @@
     final ResponseParser parser = new ResponseParser(_factory.createRecord(), getSolrConfig(), ID_FIELD);

     {

       final Record result = parser.toRecord(queryResponse);

-      final AnyMap suggestions =

-        result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE).getMap(ResponseAccessor.RESPONSE)

-          .getMap(SolrConstants.SPELLCHECK).getMap(SolrConstants.SUGGESTIONS);

+      final AnyMap suggestions = result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE)

+        .getMap(ResponseAccessor.RESPONSE).getMap(SolrConstants.SPELLCHECK).getMap(SolrConstants.SUGGESTIONS);

       assertNotNull(suggestions);

       final AnyMap olktimer = suggestions.getMap("Olktimer");

       assertNotNull(olktimer);

@@ -366,9 +362,8 @@
     final ResponseParser parser = new ResponseParser(_factory.createRecord(), getSolrConfig(), ID_FIELD);

     {

       final Record result = parser.toRecord(queryResponse);

-      final AnyMap spellcheck =

-        result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE).getMap(ResponseAccessor.RESPONSE)

-          .getMap(SolrConstants.SPELLCHECK);

+      final AnyMap spellcheck = result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE)

+        .getMap(ResponseAccessor.RESPONSE).getMap(SolrConstants.SPELLCHECK);

       assertNotNull(spellcheck);

       final AnyMap collations = spellcheck.getSeq(SolrConstants.COLLATIONS).getMap(0);

       assertEquals("q=query", collations.getStringValue(SolrConstants.COLLATION_QUERY));

@@ -399,9 +394,8 @@
     final ResponseParser parser = new ResponseParser(_factory.createRecord(), getSolrConfig(), ID_FIELD);

     {

       final Record result = parser.toRecord(queryResponse);

-      final AnyMap docs =

-        result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE).getMap(ResponseAccessor.RESPONSE)

-          .getMap(SolrConstants.MORE_LIKE_THIS).getMap("docs");

+      final AnyMap docs = result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE)

+        .getMap(ResponseAccessor.RESPONSE).getMap(SolrConstants.MORE_LIKE_THIS).getMap("docs");

       assertNotNull(docs);

       assertEquals(2, docs.getLongValue(SolrConstants.NUM_FOUND).intValue());

       assertEquals(1, docs.getLongValue(SolrConstants.START).intValue());

@@ -444,9 +438,8 @@
     final ResponseParser parser = new ResponseParser(_factory.createRecord(), getSolrConfig(), ID_FIELD);

     {

       final Record result = parser.toRecord(queryResponse);

-      final AnyMap debug =

-        result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE).getMap(ResponseAccessor.RESPONSE)

-          .getMap(SolrConstants.DEBUG);

+      final AnyMap debug = result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE)

+        .getMap(ResponseAccessor.RESPONSE).getMap(SolrConstants.DEBUG);

       assertNotNull(debug);

       assertEquals("value1", debug.getStringValue("key1"));

       assertEquals("value2", debug.getStringValue("key2"));

@@ -490,9 +483,8 @@
     final ResponseParser parser = new ResponseParser(_factory.createRecord(), getSolrConfig(), ID_FIELD);

     {

       final Record result = parser.toRecord(queryResponse);

-      final AnyMap statsFieldEntry =

-        result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE).getMap(ResponseAccessor.RESPONSE)

-          .getMap(SolrConstants.STATS).getMap("statsFieldEntry");

+      final AnyMap statsFieldEntry = result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE)

+        .getMap(ResponseAccessor.RESPONSE).getMap(SolrConstants.STATS).getMap("statsFieldEntry");

       assertNotNull(statsFieldEntry);

       assertEquals(-1, statsFieldEntry.getLongValue(SolrConstants.MIN).intValue());

       assertEquals(2, statsFieldEntry.getLongValue(SolrConstants.MAX).intValue());

@@ -539,9 +531,8 @@
       assertEquals(1, result.getMetadata().getLongValue(SearchResultConstants.COUNT).intValue());

       final AnyMap record = result.getMetadata().getSeq(SearchResultConstants.RECORDS).getMap(0);

       assertEquals("document1", record.getStringValue(ID_FIELD));

-      final AnySeq text =

-        record.getMap(SearchResultConstants.HIGHLIGHT).getMap("values")

-          .getSeq(SearchResultConstants.HIGHLIGHT_TEXT);

+      final AnySeq text = record.getMap(SearchResultConstants.HIGHLIGHT).getMap("values")

+        .getSeq(SearchResultConstants.HIGHLIGHT_TEXT);

       assertNotNull(text);

       assertEquals("highlight1", text.getStringValue(0));

       assertEquals("highlight2", text.getStringValue(1));

diff --git a/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/test/AllTests.java b/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/test/AllTests.java
index dc3de05..bdcb9c5 100755
--- a/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/test/AllTests.java
+++ b/core/org.eclipse.smila.solr.test/code/src/org/eclipse/smila/solr/test/AllTests.java
@@ -5,9 +5,6 @@
  **********************************************************************************************************************/

 package org.eclipse.smila.solr.test;

 

-import junit.framework.Test;

-import junit.framework.TestSuite;

-

 import org.eclipse.smila.solr.SolrConfig_Test;

 import org.eclipse.smila.solr.SolrUtils_Test;

 import org.eclipse.smila.solr.params.ParamsHelper_Test;

@@ -18,11 +15,15 @@
 import org.eclipse.smila.solr.query.QueryTransformer_Test;

 import org.eclipse.smila.solr.query.SolrQueryBuilder_Test;

 import org.eclipse.smila.solr.search.ResponseAccessor_Test;

-import org.eclipse.smila.solr.search.SolrResponseParser_Test;

+import org.eclipse.smila.solr.search.ResponseParser_Grouping_Test;

+import org.eclipse.smila.solr.search.ResponseParser_Test;

 import org.eclipse.smila.solr.server.CloudServers_Test;

 import org.eclipse.smila.solr.server.HttpServers_Test;

 import org.eclipse.smila.solr.update.SolrDocumentConverter_Test;

 

+import junit.framework.Test;

+import junit.framework.TestSuite;

+

 /**

  * @author tmenzel this just exists so that the default test.xml during the build is happy.

  */

@@ -40,7 +41,8 @@
     suite.addTestSuite(QueryParams_Test.class);

     suite.addTestSuite(QueryTransformer_Test.class);

     suite.addTestSuite(SolrUtils_Test.class);

-    suite.addTestSuite(SolrResponseParser_Test.class);

+    suite.addTestSuite(ResponseParser_Test.class);

+    suite.addTestSuite(ResponseParser_Grouping_Test.class);

     suite.addTestSuite(SearchParams_Test.class);

     suite.addTestSuite(ParamsHelper_Test.class);

     suite.addTestSuite(ResponseAccessor_Test.class);

diff --git a/core/org.eclipse.smila.solr/code/src/org/eclipse/smila/solr/SolrConfig.java b/core/org.eclipse.smila.solr/code/src/org/eclipse/smila/solr/SolrConfig.java
index c2cc595..fba958b 100755
--- a/core/org.eclipse.smila.solr/code/src/org/eclipse/smila/solr/SolrConfig.java
+++ b/core/org.eclipse.smila.solr/code/src/org/eclipse/smila/solr/SolrConfig.java
@@ -44,6 +44,12 @@
 

   public static final String FETCH_FACET_FIELD_TYPE = "ResponseParser.fetchFacetFieldType";

 

+  public static final String PROCESS_GROUP_VALUE_NULL = "ResponseParser.processGroupValueNull";

+

+  public static final String GROUP_VALUE_NULL = "ResponseParser.groupValueNull";

+

+  public static final String GROUP_VALUE_NULL_DEFAULT = "<null>";

+

   // CloudSolrServer

 

   public static final String ZK_HOST = "CloudSolrServer.zkHost";

@@ -137,6 +143,16 @@
     return fetchFacetFieldType != null ? fetchFacetFieldType.booleanValue() : false;

   }

 

+  public boolean isProcessGroupValueNull() {

+    final Boolean processGroupValueNull = _config.getBooleanValue(PROCESS_GROUP_VALUE_NULL);

+    return processGroupValueNull != null ? processGroupValueNull.booleanValue() : false;

+  }

+

+  public String getGroupValueNull() {

+    final String groupValueNull = _config.getStringValue(GROUP_VALUE_NULL);

+    return groupValueNull != null ? groupValueNull : GROUP_VALUE_NULL_DEFAULT;

+  }

+

   // CloudSolrServer

 

   public String getCloudSolrServerZkHost() {

diff --git a/core/org.eclipse.smila.solr/code/src/org/eclipse/smila/solr/search/ResponseParser.java b/core/org.eclipse.smila.solr/code/src/org/eclipse/smila/solr/search/ResponseParser.java
index 22d20f4..19dbeee 100755
--- a/core/org.eclipse.smila.solr/code/src/org/eclipse/smila/solr/search/ResponseParser.java
+++ b/core/org.eclipse.smila.solr/code/src/org/eclipse/smila/solr/search/ResponseParser.java
@@ -85,8 +85,8 @@
   }
 
   private AnyMap getResponseMap() {
-    return _result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE, true)
-      .getMap(ResponseAccessor.RESPONSE, true);
+    return _result.getMetadata().getMap(SolrParams.SOLR_PARAMETER_ATTRIBUTE, true).getMap(ResponseAccessor.RESPONSE,
+      true);
   }
 
   @SuppressWarnings("unchecked")
@@ -264,7 +264,8 @@
       final String fieldName = intervalFacet.getField();
       final AnySeq facet = addFacet(fieldName);
       // add facet values
-      for (final org.apache.solr.client.solrj.response.IntervalFacet.Count countObj : intervalFacet.getIntervals()) {
+      for (final org.apache.solr.client.solrj.response.IntervalFacet.Count countObj : intervalFacet
+        .getIntervals()) {
         final String value = countObj.getKey();
         final long count = countObj.getCount();
         addFacetValue(facet, value, count);
@@ -278,7 +279,7 @@
         return FieldInfoCache.getFieldInfo(_index, fieldName).getTypeAsValueType();
       } catch (InterruptedException | IOException exception) {
         if (_log.isWarnEnabled()) {
-          final String message = String.format("Error getting value type for fieldName: s%.", fieldName);
+          final String message = String.format("Error getting value type for fieldName: %s.", fieldName);
           _log.warn(message, exception);
         }
       }
@@ -312,7 +313,17 @@
       }
       final DataFactory factory = group.getFactory();
       for (Group solrGroup : command.getValues()) {
-        final Value value = factory.autoConvertValue(solrGroup.getGroupValue());
+        // get group value and check for null
+        String groupValue = solrGroup.getGroupValue();
+        if (groupValue == null) {
+          // skip group value if 'processNullGroupValue ' is not configured
+          if (!_config.isProcessGroupValueNull()) {
+            continue;
+          }
+          // otherwise get 'nullGroupValue' or use default <null>
+          groupValue = _config.getGroupValueNull();
+        }
+        final Value value = factory.autoConvertValue(groupValue);
         final SolrDocumentList documents = solrGroup.getResult();
         final Long count = documents.getNumFound();
         final AnySeq results = factory.createAnySeq();
diff --git a/core/org.eclipse.smila.solr/solr-config.json b/core/org.eclipse.smila.solr/solr-config.json
index 090572b..48aa9af 100755
--- a/core/org.eclipse.smila.solr/solr-config.json
+++ b/core/org.eclipse.smila.solr/solr-config.json
@@ -8,5 +8,7 @@
     "CloudSolrServer.zkHost":"localhost:9983",

     "CloudSolrServer.updatesToLeaders":"true",

     "EmbeddedSolrServer.solrHome":"configuration\\org.eclipse.smila.solr\\solr_home",

-    "HttpSolrServer.baseUrl":"http://localhost:8983/"

+    "HttpSolrServer.baseUrl":"http://localhost:8983/",

+    "ResponseParser.processGroupValueNull":"false",

+    "ResponseParser.groupValueNull":"<null>"

 }
\ No newline at end of file