You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/03/13 06:33:24 UTC

[camel] 01/02: CAMEL-19128: camel-jbang - Add version command

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 0a103d6b415add32a8893c310c3044e3d2af4a4b
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Mar 12 15:07:46 2023 +0100

    CAMEL-19128: camel-jbang - Add version command
---
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   8 +-
 .../core/commands/version/VersionCommand.java      |  37 ++++++
 .../jbang/core/commands/version/VersionGet.java    |  54 ++++++++
 .../jbang/core/commands/version/VersionList.java   | 138 +++++++++++++++++++++
 .../camel/dsl/jbang/core/common/VersionHelper.java |  36 +++++-
 .../camel/main/download/DependencyDownloader.java  |  12 ++
 .../main/download/MavenDependencyDownloader.java   |  71 +++++++++++
 .../java/org/apache/camel/main/util/XmlHelper.java |  63 ++++++++++
 8 files changed, 412 insertions(+), 7 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index e75bc172137..03eb94094e0 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -67,6 +67,9 @@ import org.apache.camel.dsl.jbang.core.commands.process.ListProcess;
 import org.apache.camel.dsl.jbang.core.commands.process.ListService;
 import org.apache.camel.dsl.jbang.core.commands.process.ListVault;
 import org.apache.camel.dsl.jbang.core.commands.process.StopProcess;
+import org.apache.camel.dsl.jbang.core.commands.version.VersionCommand;
+import org.apache.camel.dsl.jbang.core.commands.version.VersionGet;
+import org.apache.camel.dsl.jbang.core.commands.version.VersionList;
 import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
 import picocli.CommandLine;
 import picocli.CommandLine.Command;
@@ -135,7 +138,10 @@ public class CamelJBangMain implements Callable<Integer> {
                         .addSubcommand("list", new CommandLine(new ConfigList(main)))
                         .addSubcommand("get", new CommandLine(new ConfigGet(main)))
                         .addSubcommand("unset", new CommandLine(new ConfigUnset(main)))
-                        .addSubcommand("set", new CommandLine(new ConfigSet(main))));
+                        .addSubcommand("set", new CommandLine(new ConfigSet(main))))
+                .addSubcommand("version", new CommandLine(new VersionCommand(main))
+                        .addSubcommand("get", new CommandLine(new VersionGet(main)))
+                        .addSubcommand("list", new CommandLine(new VersionList(main))));
 
         commandLine.getCommandSpec().versionProvider(() -> {
             CamelCatalog catalog = new DefaultCamelCatalog();
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionCommand.java
new file mode 100644
index 00000000000..d305b45866c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionCommand.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.version;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "version",
+                     description = "Manage Camel versions (use config --help to see sub commands)")
+public class VersionCommand extends CamelCommand {
+
+    public VersionCommand(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer call() throws Exception {
+        // defaults to get
+        new CommandLine(new VersionGet(getMain())).execute();
+        return 0;
+    }
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionGet.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionGet.java
new file mode 100644
index 00000000000..23d0a283650
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionGet.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.version;
+
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
+import org.apache.camel.dsl.jbang.core.common.RuntimeCompletionCandidates;
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "get", description = "Displays current Camel version")
+public class VersionGet extends CamelCommand {
+
+    @CommandLine.Option(names = { "--runtime" }, completionCandidates = RuntimeCompletionCandidates.class,
+                        description = "Runtime (spring-boot, quarkus, or camel-main)")
+    protected String runtime;
+
+    public VersionGet(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer call() throws Exception {
+        CamelCatalog catalog = new DefaultCamelCatalog();
+        String v = catalog.getCatalogVersion();
+        System.out.println("Camel CLI version: " + v);
+
+        CommandLineHelper.loadProperties(properties -> {
+            String uv = properties.getProperty("camel-version");
+            if (uv != null) {
+                System.out.println("User configuration Camel version: " + uv);
+            }
+        });
+
+        return 0;
+    }
+
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
new file mode 100644
index 00000000000..7e6ab2be88c
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.version;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.github.freva.asciitable.AsciiTable;
+import com.github.freva.asciitable.Column;
+import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.RuntimeCompletionCandidates;
+import org.apache.camel.dsl.jbang.core.common.VersionHelper;
+import org.apache.camel.main.KameletMain;
+import org.apache.camel.main.download.MavenDependencyDownloader;
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "list", description = "Displays available Camel versions")
+public class VersionList extends CamelCommand {
+
+    private static final String MINIMUM_VERSION = "3.14.0";
+    private static final String MINIMUM_QUARKUS_VERSION = "2.13.0";
+
+    // TODO: Filter for minimum camel version
+    // TODO: grab Q and SB runtime version
+
+    @CommandLine.Option(names = { "--sort" },
+                        description = "Sort by version", defaultValue = "version")
+    String sort;
+
+    @CommandLine.Option(names = { "--runtime" }, completionCandidates = RuntimeCompletionCandidates.class,
+                        description = "Runtime (spring-boot, quarkus, or camel-main)")
+    protected String runtime;
+
+    @CommandLine.Option(names = { "--repo", "--repos" }, description = "Maven repository for downloading available versions")
+    String repo;
+
+    public VersionList(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer call() throws Exception {
+        configureLoggingOff();
+        KameletMain main = new KameletMain();
+
+        List<String> versions;
+        try {
+            main.start();
+
+            // use kamelet-main to download from maven
+            MavenDependencyDownloader downloader = main.getCamelContext().hasService(MavenDependencyDownloader.class);
+
+            String g = "org.apache.camel";
+            String a = "camel-catalog";
+            if ("spring-boot".equalsIgnoreCase(runtime)) {
+                g = "org.apache.camel.springboot";
+                a = "camel-catalog-provider-springboot";
+            } else if ("quarkus".equalsIgnoreCase(runtime)) {
+                g = "org.apache.camel.quarkus";
+                a = "camel-quarkus-catalog";
+            }
+
+            versions = downloader.downloadAvailableVersions(g, a, repo);
+            versions = versions.stream().filter(this::acceptVersion).collect(Collectors.toList());
+
+            main.stop();
+        } catch (Exception e) {
+            System.out.println("Error downloading available Camel versions");
+            return 1;
+        }
+
+        List<Row> rows = new ArrayList<>();
+        for (String v : versions) {
+            Row row = new Row();
+            rows.add(row);
+            row.coreVersion = v;
+        }
+
+        // sort rows
+        rows.sort(this::sortRow);
+
+        System.out.println(AsciiTable.getTable(AsciiTable.NO_BORDERS, rows, Arrays.asList(
+                new Column().header("QUARKUS VERSION").visible("quarkus".equalsIgnoreCase(runtime)).with(r -> r.runtimeVersion),
+                new Column().header("SPRING BOOT VERSION").visible("spring-boot".equalsIgnoreCase(runtime))
+                        .with(r -> r.runtimeVersion),
+                new Column().header("CAMEL VERSION").with(r -> r.coreVersion))));
+
+        return 0;
+    }
+
+    protected int sortRow(Row o1, Row o2) {
+        String s = sort;
+        int negate = 1;
+        if (s.startsWith("-")) {
+            s = s.substring(1);
+            negate = -1;
+        }
+        switch (s) {
+            case "version":
+                String v1 = o1.runtimeVersion != null ? o1.runtimeVersion : o1.coreVersion;
+                String v2 = o2.runtimeVersion != null ? o2.runtimeVersion : o2.coreVersion;
+                return VersionHelper.compare(v1, v2) * negate;
+            default:
+                return 0;
+        }
+    }
+
+    private boolean acceptVersion(String version) {
+        String min = MINIMUM_VERSION;
+        if ("quarkus".equalsIgnoreCase(runtime)) {
+            min = MINIMUM_QUARKUS_VERSION;
+        }
+        return VersionHelper.isGE(version, min);
+    }
+
+    private static class Row {
+        String runtimeVersion;
+        String coreVersion;
+    }
+
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/VersionHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/VersionHelper.java
index cc22c2985e5..97ae5734405 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/VersionHelper.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/VersionHelper.java
@@ -24,8 +24,12 @@ public final class VersionHelper {
     }
 
     public static boolean isGE(String source, String target) {
+        return compare(source, target) >= 0;
+    }
+
+    public static int compare(String source, String target) {
         if (source == null || target == null) {
-            return false;
+            return 0;
         }
         String s1 = StringHelper.before(source, ".");
         String s2 = StringHelper.after(source, ".");
@@ -39,7 +43,18 @@ public final class VersionHelper {
             t1 = StringHelper.before(target, ",");
             t2 = StringHelper.after(target, ",");
         }
-
+        String s3 = StringHelper.after(s2, ".");
+        if (s3 != null) {
+            s2 = StringHelper.before(s2, ".");
+        } else {
+            s3 = "";
+        }
+        String t3 = StringHelper.after(t2, ".");
+        if (t3 != null) {
+            t2 = StringHelper.before(t2, ".");
+        } else {
+            t3 = "";
+        }
         // convert to 2-digit numbers
         if (s1.length() < 2) {
             s1 = "0" + s1;
@@ -47,16 +62,25 @@ public final class VersionHelper {
         if (s2.length() < 2) {
             s2 = "0" + s2;
         }
+        if (s2.length() < 2) {
+            s2 = "0" + s2;
+        }
+        if (s3.length() < 2) {
+            s3 = "0" + s3;
+        }
         if (t1.length() < 2) {
             t1 = "0" + t1;
         }
         if (t2.length() < 2) {
             t2 = "0" + t2;
         }
+        if (t3.length() < 2) {
+            t3 = "0" + t3;
+        }
 
-        String s = s1 + s2;
-        String t = t1 + t2;
-        int n = s.compareTo(t);
-        return n >= 0;
+        String s = s1 + s2 + s3;
+        String t = t1 + t2 + t3;
+        return s.compareTo(t);
     }
+
 }
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java
index 1ebf173e5a3..ccab96ea85f 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.main.download;
 
+import java.util.List;
+
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.StaticService;
 
@@ -120,6 +122,16 @@ public interface DependencyDownloader extends CamelContextAware, StaticService {
      */
     MavenArtifact downloadArtifact(String groupId, String artifactId, String version);
 
+    /**
+     * Downloads the available versions for the given maven artifact
+     *
+     * @param  groupId    maven group id
+     * @param  artifactId maven artifact id
+     * @param  repo       to use specific maven repository instead of maven central
+     * @return            list of versions of the given artifact
+     */
+    List<String> downloadAvailableVersions(String groupId, String artifactId, String repo);
+
     /**
      * Checks whether the dependency is already on the classpath
      *
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
index fbe9edcb7d8..b0125b04f31 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
@@ -37,9 +37,17 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Collectors;
 
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.main.injection.DIRegistry;
+import org.apache.camel.main.util.XmlHelper;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.FileUtil;
@@ -148,6 +156,8 @@ import org.eclipse.aether.internal.impl.synccontext.named.NameMapper;
 import org.eclipse.aether.internal.impl.synccontext.named.NameMappers;
 import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactory;
 import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactoryImpl;
+import org.eclipse.aether.metadata.DefaultMetadata;
+import org.eclipse.aether.metadata.Metadata;
 import org.eclipse.aether.named.NamedLockFactory;
 import org.eclipse.aether.named.providers.FileLockNamedLockFactory;
 import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory;
@@ -164,6 +174,8 @@ import org.eclipse.aether.resolution.ArtifactRequest;
 import org.eclipse.aether.resolution.DependencyRequest;
 import org.eclipse.aether.resolution.DependencyResolutionException;
 import org.eclipse.aether.resolution.DependencyResult;
+import org.eclipse.aether.resolution.MetadataRequest;
+import org.eclipse.aether.resolution.MetadataResult;
 import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
 import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
 import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
@@ -452,6 +464,27 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         return null;
     }
 
+    @Override
+    public List<String> downloadAvailableVersions(String groupId, String artifactId, String repo) {
+        String gav = groupId + ":" + artifactId;
+        LOG.debug("DownloadAvailableVersions: {}", gav);
+
+        // repo 0 is maven central
+        RemoteRepository repository = remoteRepositories.get(0);
+        if (repo != null) {
+            List<RemoteRepository> extra = resolveExtraRepositories(repo);
+            if (!extra.isEmpty()) {
+                repository = extra.get(0);
+            }
+        }
+        List<String> versions = resolveAvailableVersions(groupId, artifactId, repository);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("DownloadAvailableVersions {} -> [{}]", gav, versions);
+        }
+
+        return versions;
+    }
+
     public boolean alreadyOnClasspath(String groupId, String artifactId, String version) {
         return alreadyOnClasspath(groupId, artifactId, version, true);
     }
@@ -1290,6 +1323,44 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         }
     }
 
+    public List<String> resolveAvailableVersions(
+            String groupId, String artifactId, RemoteRepository repository) {
+
+        List<String> answer = new ArrayList<>();
+
+        try {
+            MetadataRequest ar = new MetadataRequest();
+            ar.setRepository(repository);
+            ar.setFavorLocalRepository(false);
+            ar.setMetadata(new DefaultMetadata(groupId, artifactId, "maven-metadata.xml", Metadata.Nature.RELEASE));
+
+            List<MetadataResult> result = repositorySystem.resolveMetadata(repositorySystemSession, List.of(ar));
+            for (MetadataResult mr : result) {
+                if (mr.isResolved() && mr.getMetadata().getFile() != null) {
+                    File f = mr.getMetadata().getFile();
+                    if (f.exists() && f.isFile()) {
+                        DocumentBuilderFactory dbf = XmlHelper.createDocumentBuilderFactory();
+                        DocumentBuilder db = dbf.newDocumentBuilder();
+                        Document dom = db.parse(f);
+                        NodeList nl = dom.getElementsByTagName("version");
+                        for (int i = 0; i < nl.getLength(); i++) {
+                            Element node = (Element) nl.item(i);
+                            String v = node.getTextContent();
+                            if (v != null) {
+                                answer.add(v);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            String msg = "Cannot resolve available versions in " + repository.getUrl();
+            throw new DownloadException(msg, e);
+        }
+
+        return answer;
+    }
+
     private static class AcceptAllDependencyFilter implements DependencyFilter {
         @Override
         public boolean accept(DependencyNode node, List<DependencyNode> parents) {
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/util/XmlHelper.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/util/XmlHelper.java
new file mode 100644
index 00000000000..52b843abfcf
--- /dev/null
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/util/XmlHelper.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.main.util;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.camel.util.ObjectHelper;
+
+public final class XmlHelper {
+
+    private XmlHelper() {
+    }
+
+    public static DocumentBuilderFactory createDocumentBuilderFactory() {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        factory.setIgnoringElementContentWhitespace(true);
+        factory.setIgnoringComments(true);
+        try {
+            // Set secure processing
+            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+        } catch (ParserConfigurationException e) {
+        }
+        try {
+            // Disable the external-general-entities by default
+            factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+        } catch (ParserConfigurationException e) {
+        }
+        try {
+            // Disable the external-parameter-entities by default
+            factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+        } catch (ParserConfigurationException e) {
+        }
+        // setup the SecurityManager by default if it's apache xerces
+        try {
+            Class<?> smClass = ObjectHelper.loadClass("org.apache.xerces.util.SecurityManager");
+            if (smClass != null) {
+                Object sm = smClass.getDeclaredConstructor().newInstance();
+                // Here we just use the default setting of the SeurityManager
+                factory.setAttribute("http://apache.org/xml/properties/security-manager", sm);
+            }
+        } catch (Exception e) {
+        }
+        return factory;
+    }
+
+}