Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RuleManager.matchAs with two parameters - Object, T ruleListHandle throws NullPointerException #395

Closed
georgeajit opened this issue Mar 7, 2016 · 7 comments

Comments

@georgeajit
Copy link
Contributor

When a test method uses the following snippet from RuleManager class

RuleDefinitionList matchedRules = ruleMatchMgr.matchAs(inputStreamMatch, matchedRulesDefList);

which is of the following JavaDocs description

<T extends RuleListReadHandle> T matchAs(Object content, T ruleListHandle)

JerseyServices class throws a NullPointerException. Here is the stack trace when the test method with above snippet is run.

java.lang.NullPointerException
    at com.marklogic.client.impl.JerseyServices.match(JerseyServices.java:5102)
    at com.marklogic.client.impl.RuleManagerImpl.match(RuleManagerImpl.java:277)
    at com.marklogic.client.impl.RuleManagerImpl.matchAs(RuleManagerImpl.java:243)
    at com.marklogic.client.impl.RuleManagerImpl.matchAs(RuleManagerImpl.java:213)
    at com.marklogic.client.functionaltest.TestDatabaseClientConnection.testRuleManagerMatchAs(TestDatabaseClientConnection.java:721)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

JerseyServices' match might need to handle the case when no candidate rules are passed.

@Override
    public InputStream match(StructureWriteHandle document,
            String[] candidateRules, String mimeType, ServerTransform transform) {
        MultivaluedMap<String, String> params = new MultivaluedMapImpl();

        HandleImplementation baseHandle = HandleAccessor.checkHandle(document, "match");
        if (candidateRules.length > 0) {
            for (String candidateRule : candidateRules) {
                params.add("rule", candidateRule);
            }
        }
@sammefford
Copy link
Contributor

Ajit, is there a vaild need to pass in null? If not, I'm ok with this throwing a NullPointerException . . . that's common even within Java's core APIs. I prefer IllegalArgumentException but I'm not seeing a pressing need to change that everywhere.

@georgeajit
Copy link
Contributor Author

Sam,

We have published the following method signature:

<T extends RuleListReadHandle> T matchAs(Object content, T ruleListHandle)

and that was the reason for the test.

@georgeajit
Copy link
Contributor Author

Here is a simple test method to reproduce the issue.

public void testRuleManagerMatchAs() throws IOException, ParserConfigurationException, SAXException, XpathException, TransformerException
    {
        System.out.println("Running testRuleManagerMatchAs");       
        String[] filenames = {"constraint1.xml", "constraint2.xml", "constraint3.xml", "constraint4.xml", "constraint5.xml"};
        String[] rules = new String[] {"RULE-TEST-1","RULE-TEST-2"};

        //DatabaseClient client = DatabaseClientFactory.newClient("localhost", Uberport, UberdbName, "eval-user", "x", Authentication.DIGEST);
        DatabaseClient client = DatabaseClientFactory.newClient("localhost", 8011, "rest-admin", "x", Authentication.DIGEST);

        // write docs
        for(String filename : filenames) {
            writeDocumentUsingInputStreamHandle(client, filename, "/raw-alert/", "XML");
        }

        // create a manager for configuring rules
        RuleManager ruleMgr = client.newRuleManager();

        // create handle
        InputStreamHandle ruleHandle1 = new InputStreamHandle();
        InputStreamHandle ruleHandle2 = new InputStreamHandle();

        // get the rule file
        InputStream inputStream1 = new FileInputStream("src/test/java/com/marklogic/client/functionaltest/rules/alertRule1.xml");
        InputStream inputStream2 = new FileInputStream("src/test/java/com/marklogic/client/functionaltest/rules/alertRule2.xml");

        ruleHandle1.set(inputStream1);
        ruleHandle2.set(inputStream2);

        // write the rule to the database
        ruleMgr.writeRule(rules[0], ruleHandle1);
        ruleMgr.writeRule(rules[1], ruleHandle2);

        // create a manager for document search criteria
        QueryManager queryMgr = client.newQueryManager();

        // create a manager for matching rules
        RuleManager ruleMatchMgr = client.newRuleManager();

        // match the rules against the documents qualified by the criteria
        RuleDefinitionList matchedRulesDefList = new RuleDefinitionList();
        InputStream inputStreamMatch = new FileInputStream("src/test/java/com/marklogic/client/functionaltest/rules/alertRule2.xml");
        RuleDefinitionList matchedRules = ruleMatchMgr.matchAs(inputStreamMatch, matchedRulesDefList); // Git Issue 395

        System.out.println(matchedRules.size());
        String expected = "";

        // iterate over the matched rules
        Iterator<RuleDefinition> ruleItr = matchedRules.iterator();
        while (ruleItr.hasNext()) {
            RuleDefinition rule = ruleItr.next();
            System.out.println(
                    "document criteria matched rule "+
                            rule.getName()+" with metadata "+rule.getMetadata()
                    );
            expected = expected + rule.getName() + " - " + rule.getMetadata() + " | ";
        }
        System.out.println(expected);

        // release client
        client.release();   
    }

Here are the documents inserted into the database.
constraint1.xml

<root>
  <title>Vannevar Bush</title>
  <popularity>5</popularity>
  <id>0011</id>
  <date xmlns="http://purl.org/dc/elements/1.1/">2005-01-01</date>
  <price xmlns="http://cloudbank.com" amt="0.1"/>
  <p>Vannevar Bush wrote an article for The Atlantic Monthly</p>
</root>

constraint2.xml

<root>
  <title>The Bush article</title>
  <popularity>4</popularity>
  <id>0012</id>
  <date xmlns="http://purl.org/dc/elements/1.1/">2006-02-02</date>
  <price xmlns="http://cloudbank.com" amt="0.12"/>
  <p>The Bush article described a device called a Memex.</p>
</root>

constraint3.xml

<root>
  <title>For 1945</title>
  <popularity>3</popularity>
  <id>0113</id>
  <date xmlns="http://purl.org/dc/elements/1.1/">2007-03-03</date>
  <price xmlns="http://cloudbank.com" amt="1.23"/>
  <p>For 1945, the thoughts expressed in The Atlantic Monthly were groundbreaking.</p>
</root>

constraint4.xml

<root>
  <title>Vannevar served</title>
  <popularity>5</popularity>
  <id>0024</id>
  <date xmlns="http://purl.org/dc/elements/1.1/">2008-04-04</date>
  <price xmlns="http://cloudbank.com" amt="12.34"/>
  <p>Vannevar served as a prominent policymaker and public intellectual.</p>
</root>

constraint5.xml

<root>
  <title>The memex</title>
  <popularity>5</popularity>
  <id>0026</id>
  <date xmlns="http://purl.org/dc/elements/1.1/">2009-05-05</date>
  <price xmlns="http://cloudbank.com" amt="123.45"/>
  <p>The Memex, unfortunately, had no automated search feature.</p>
</root>

Rules written to the database are
Rule Name:- RULE-TEST-1

<rapi:rule xmlns:rapi="http://marklogic.com/rest-api">
  <rapi:name>RULE-TEST-1</rapi:name>
  <rapi:description>rule for test1</rapi:description>
  <search:search xmlns:search="http://marklogic.com/appservices/search">
    <search:query>
      <search:word-constraint-query>
        <search:constraint-name>intitle</search:constraint-name>
        <search:text>Vannevar</search:text>
      </search:word-constraint-query>
    </search:query>
    <search:options>
      <search:constraint name="intitle">
        <search:word>
          <search:element name="title" ns=""/>
        </search:word>
      </search:constraint>
    </search:options>
  </search:search>
  <rapi:rule-metadata>
    <rule-number>one</rule-number>
  </rapi:rule-metadata>
</rapi:rule>

Rule Name:- RULE-TEST-2

<rapi:rule xmlns:rapi="http://marklogic.com/rest-api">
  <rapi:name>RULE-TEST-2</rapi:name>
  <rapi:description>rule for test2</rapi:description>
  <search:search xmlns:search="http://marklogic.com/appservices/search">
    <search:query>
      <search:range-constraint-query>
        <search:constraint-name>date</search:constraint-name>
        <search:value>2005-01-01</search:value>
      </search:range-constraint-query>
    </search:query>
    <search:options>
      <search:constraint name="date">
        <search:range type="xs:date" facet="false">
          <search:element ns="http://purl.org/dc/elements/1.1/" name="date"/>
        </search:range>
      </search:constraint>
    </search:options>
  </search:search>
  <rapi:rule-metadata>
    <rule-number>two</rule-number>
  </rapi:rule-metadata>
</rapi:rule>

@sammefford
Copy link
Contributor

Ajit, can you tell me what writeDocumentUsingInputStreamHandle does? Or translate it into Java Client API code?

@georgeajit
Copy link
Contributor Author

Sam,
Here are the support methods used in the above test method.

public DocumentManager documentManagerSelector(DatabaseClient client, DocumentManager docMgr, String type)
    {
        // create doc manager
        if(type == "XML")
        {
            docMgr = client.newXMLDocumentManager();
        }
        else if(type == "Text")
        {   
            docMgr = client.newTextDocumentManager();
        }
        else if(type == "JSON")
        {   
            docMgr = client.newJSONDocumentManager();
        }
        else if(type == "Binary")
        {   
            docMgr = client.newBinaryDocumentManager();
        }
        else if (type == "JAXB") {
            docMgr = client.newXMLDocumentManager();
        }
        else 
        { 

            System.out.println("Invalid type");
        }

        return docMgr;
    }

    /**
     * Write document using InputStreamHandle
     * @param client
     * @param filename
     * @param uri
     * @param type
     * @throws FileNotFoundException 
     */
    public void writeDocumentUsingInputStreamHandle(DatabaseClient client, String filename, String uri, String type) throws FileNotFoundException
    {
        // create doc manager
        DocumentManager docMgr = null;
        docMgr = documentManagerSelector(client, docMgr, type); 

        // create handle
        InputStreamHandle contentHandle = new InputStreamHandle();

        // get the file
        InputStream inputStream = new FileInputStream("src/test/java/com/marklogic/client/functionaltest/data/" + filename);

        // set uri
        String docId = uri + filename;

        contentHandle.set(inputStream);

        // write doc
        docMgr.write(docId, contentHandle);

        System.out.println("Write " + docId + " to database");
    }

sammefford added a commit that referenced this issue Mar 8, 2016
@sammefford sammefford added test and removed verify labels Mar 8, 2016
@sammefford sammefford assigned georgeajit and unassigned sammefford Mar 8, 2016
@sammefford
Copy link
Contributor

Good find, Ajit.

@georgeajit georgeajit added ship and removed test labels Mar 9, 2016
@georgeajit georgeajit removed their assignment Mar 9, 2016
@georgeajit
Copy link
Contributor Author

Running the above test does not produce NullPointerException.

sammefford added a commit that referenced this issue Mar 10, 2016
(cherry picked from commit ebb5e8e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants