Initialize EXISchema grammars lazily
[netconf.git] / netconf / netconf-netty-util / src / main / java / org / opendaylight / netconf / nettyutil / handler / exi / EXISchema.java
index 52f93751733b8a7d9c586d443a48f25ba5949967..72c9f1779f14395bb07a4e40eed31bf26c37f917 100644 (file)
@@ -9,10 +9,13 @@ package org.opendaylight.netconf.nettyutil.handler.exi;
 
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.base.Suppliers;
 import com.google.common.io.ByteSource;
 import com.google.common.io.Resources;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.function.Supplier;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.netconf.shaded.exificient.core.exceptions.EXIException;
 import org.opendaylight.netconf.shaded.exificient.core.grammars.Grammars;
 import org.opendaylight.netconf.shaded.exificient.grammars.GrammarFactory;
@@ -21,52 +24,72 @@ import org.opendaylight.netconf.shaded.exificient.grammars.GrammarFactory;
  * Enumeration of schema modes defined by the NETCONF EXI capability.
  */
 public enum EXISchema {
-    NONE("none", GrammarFactory.newInstance().createSchemaLessGrammars()),
-    BUILTIN("builtin", createBuiltinGrammar()),
-    BASE_1_1("base:1.1", createNetconfGrammar());
+    NONE("none") {
+        @Override
+        Grammars createGrammar() {
+            return GrammarFactory.newInstance().createSchemaLessGrammars();
+        }
+    },
+    BUILTIN("builtin") {
+        @Override
+        Grammars createGrammar() {
+            try {
+                return GrammarFactory.newInstance().createXSDTypesOnlyGrammars();
+            } catch (EXIException e) {
+                throw new IllegalStateException("Failed to create builtin grammar", e);
+            }
+        }
+    },
+    BASE_1_1("base:1.1") {
+        @Override
+        Grammars createGrammar() {
+            final ByteSource source = Resources.asByteSource(EXISchema.class.getResource("/rfc6241.xsd"));
+            try (InputStream is = source.openStream()) {
+                final Grammars g = GrammarFactory.newInstance().createGrammars(is);
+                g.setSchemaId(getOption());
+                return g;
+            } catch (EXIException | IOException e) {
+                throw new IllegalStateException("Failed to create RFC6241 grammar", e);
+            }
+        }
+    };
 
     private String option;
-    private Grammars grammar;
+    private Supplier<Grammars> grammarsSupplier;
 
-    EXISchema(final String option, final Grammars grammar) {
+    EXISchema(final String option) {
         this.option = requireNonNull(option);
-        this.grammar = requireNonNull(grammar);
+        // Grammar instantiation can be CPU-intensive, hence we instantiate it lazily through a memoizing supplier
+        this.grammarsSupplier = Suppliers.memoize(this::createGrammar);
     }
 
     final String getOption() {
         return option;
     }
 
+    /**
+     * Return the grammar associated with this EXISchema.
+     *
+     * @return An EXI grammar.
+     */
     final Grammars getGrammar() {
-        return grammar;
+        return grammarsSupplier.get();
     }
 
-    static EXISchema forOption(final String id) {
+    /**
+     * Create grammars associated with this EXISchema. This is a potentially expensive operation for internal use only,
+     * use {@link #getGrammar()} instead.
+     *
+     * @return An EXI grammar.
+     */
+    abstract Grammars createGrammar();
+
+    static @Nullable EXISchema forOption(final String id) {
         for (EXISchema s : EXISchema.values()) {
             if (id.equals(s.getOption())) {
                 return s;
             }
         }
-
         return null;
     }
-
-    private static Grammars createNetconfGrammar() {
-        final ByteSource source = Resources.asByteSource(EXISchema.class.getResource("/rfc6241.xsd"));
-        try (InputStream is = source.openStream()) {
-            final Grammars g = GrammarFactory.newInstance().createGrammars(is);
-            g.setSchemaId("base:1.1");
-            return g;
-        } catch (EXIException | IOException e) {
-            throw new IllegalStateException("Failed to create RFC6241 grammar", e);
-        }
-    }
-
-    private static Grammars createBuiltinGrammar() {
-        try {
-            return GrammarFactory.newInstance().createXSDTypesOnlyGrammars();
-        } catch (EXIException e) {
-            throw new IllegalStateException("Failed to create builtin grammar", e);
-        }
-    }
 }