1
votes

I have a Grails Plugin called 'foo' that uses another Grails Plugin called 'common'.

grails.plugin.location.'common' = "../common"

The 'common' plugin contains domain classes, as well as resource files (.properties files, xml templates, ...). These files are all located in subfolders in common/grails-app/conf/.

There's one class that implements NamespaceContext in my 'common' plugin that uses these files in order to function properly.

public class MyNamespaceContext implements NamespaceContext {

private Map<String, String> namespaces;

public MyNamespaceContext() {

    final String XML_NAMESPACES_FILE = "grails-app/conf/xml/xmlNamespaces.properties";

    try {
        Properties xmlNamespaces = new Properties();
        xmlNamespaces.load(new FileReader(XML_NAMESPACES_FILE));
        namespaces = new HashMap<String, String>((Map) xmlNamespaces);
    } catch (FileNotFoundException e) {
        throw new RuntimeException("XML namespaces file '" + XML_NAMESPACES_FILE + "' cannot be found");
    } catch (IOException e) {
        throw new RuntimeException("IOException");
    }
}

...

}

This class is used in several classes, also located in 'common' that form my domain model, implemented as xml decorators.

  public class UserXmlDecorator implements User {

    private Document xmlDocument;
    private XPath xPath;
    private final String rawXml;

    public UserXmlDecorator(String rawXml) {
        this.rawXml = rawXml;
        this.xmlDocument = XmlDocumentFactory.INSTANCE.buildXmlDocumentInUTF8(rawXml);
        this.xPath = XPathFactory.newInstance().newXPath();
        xPath.setNamespaceContext(new MyNamespaceContext());
    }

    public String getUserName() {
        try {
            XPathExpression userNameXPathExpr = xPath.compile("...");
            String userName = userNameXPathExpr.evaluate(appendixBXmlDocument);
            return userName;
        } catch (XPathExpressionException e) {
            throw new RuntimeException();
        }
    }

    public String getAge() {
        try {
            XPathExpression ageXPathExpr = xPath.compile("...");
            String age = ageXPathExpr.evaluate(appendixBXmlDocument);
            return age;
        } catch (XPathExpressionException e) {
            throw new RuntimeException();
        }
    }

When creating these decorators in my Grails Plugin 'foo', I get a FileNotFound exception, because it is looking for the template in foo/grails-app/conf/xml/xmlNamespaces.properties, instead of common/grails-app/conf/xml/xmlNamespaces.properties.

I've read Grails: How to reference a resource located inside an installed plugin? but this could not help me.

Any idea how I can solve this?

1
This seems like a design issue. Ideally, your common plugin should expose a method that the plugin foo can call. - Rohit
It might help if you update the post and add code that you're using to load the xml resource. - uchamp
I've added the relevant code pieces. - Will

1 Answers

1
votes

Solved this by putting the .properties file in the classpath instead of the conf/ directory and then using the classloader to lod the resource.

xmlNamespaces.load(this.getClass().getClassLoader().getResourceAsStream(XML_NAMESPACES_FILE));