How to enable https for jetty using XmlConfiguration? - java

We have an OSGi based server, from where we use an embedded jetty to handle webtraffic.
I'm using the XmlConfiguration to create a jetty server instance, see the code below.
The configStream is the from the jetty-http.xml which is read per default from our plugin or from a custom location.
Now I'm trying to enable https for the server. I would like to load the jetty-ssl.xml and jetty-https.xml the same as jetty-http.xml.
How can I do that? I can't load another stream into the XmlConfiguration.
Is there another approach, maybe without XmlConfiguration?
XmlConfiguration xmlConfig = new XmlConfiguration(configStream);
Object root = xmlConfig.configure();
if (!(root instanceof Server)) {
throw new IllegalArgumentException("expected a Server object as a root for server configuration"); //$NON-NLS-1$
}
server = (Server) root;

I found a solution, see the code below.
XmlConfiguration can be used for all xml files, if two of them create a Server instance (e.g. jetty.xml and jetty-ssl.xml), only one Server is created and configurations/beans are added to the same instance.
List<String> configurations = new ArrayList<String>();
configurations.add("jetty.xml"); //$NON-NLS-1$
// use pre-configured jetty xml files to construct a server instance
if (System.getProperty("jetty.sslContext.keyStorePath") != null) { //$NON-NLS-1$
configurations.add("jetty-ssl.xml"); //$NON-NLS-1$
configurations.add("jetty-ssl-context.xml"); //$NON-NLS-1$
configurations.add("jetty-https.xml"); //$NON-NLS-1$
} else {
configurations.add("jetty-http.xml"); //$NON-NLS-1$
}
XmlConfiguration last = null;
List<Object> objects = new ArrayList<Object>();
for (String configFile : configurations) {
InputStream configStream = null;
File xmlConfiguration = new File(webserverHome, CONFIG_LOCATION + configFile);
if (xmlConfiguration.exists()) {
configStream = new FileInputStream(xmlConfiguration);
logger.info("Using custom XML configuration {}", xmlConfiguration); //$NON-NLS-1$
} else {
// configStream = ... // read from bundle
logger.info("Using default XML configuration {}/{}", Activator.PLUGIN_ID, CONFIG_LOCATION + configFile); //$NON-NLS-1$
}
XmlConfiguration configuration = new XmlConfiguration(configStream);
if (last != null) {
configuration.getIdMap().putAll(last.getIdMap());
}
objects.add(configuration.configure());
last = configuration;
}
// first object is a Server instance because of the jetty.xml
server = (Server) objects.get(0);

Related

Deploy a writable properties file in jpackaged Java application

I have a Java client application that I am going to package as a stand-alone application using jpackage.
But the application has a Properties file which must be both read and written to by the application. My initial attempts to do this run in the IDE, but when I package the application it fails because the location of the properties file is actually located inside the packaged .jar.
Is there a canonical / "right" way to maintain a writable properties file with a jpackaged application?
Package default settings in your application. At runtime, store a writable copy of them in a known file location, typically in a directory that is a descendant of the user’s home directory:
String applicationName = /* ... */;
Properties configuration;
String os = System.getProperty("os.name");
String home = System.getProperty("user.home");
Path localSettingsDir;
if (os.contains("Mac")) {
localSettingsDir = Path.of(home, "Library", "Application Support");
} else if (os.contains("Windows")) {
String appData = System.getenv("APPDATA");
if (appData != null) {
localSettingsDir = Path.of(appData);
} else {
localSettingsDir = Path.of(home, "AppData", "Roaming");
}
} else {
String configHome = System.getenv("XDG_CONFIG_HOME");
if (configHome != null) {
localSettingsDir = Path.of(configHome);
if (!localSettingsDir.isAbsolute()) {
localSettingsDir = Path.of(home, ".config");
}
} else {
localSettingsDir = Path.of(home, ".config");
}
}
Path localSettings = localSettingsDir.resolve(
Path.of(applicationName, "config.properties"));
configuration = new Properties();
if (!Files.exists(localSettings)) {
Files.createDirectories(localSettings.getParent());
try (InputStream defaultSettings =
MyApplication.class.getResourceAsStream("config.properties")) {
Files.copy(defaultSettings, localSettings);
}
}
try (Reader settingsSource = Files.newBufferedReader(localSettings)) {
configuration.load(settingsSource);
}
For more details on determining a system’s application configuration directory, see Find place for dedicated application folder.

How to create an InitialDirContext in an OSGi component inside felix (v603) running on top of jdk15

I am in the process of upgrading my jdk8 code to jdk15 and have most of the dependencies and config settings working but I am struggling with the creation of a new InitialDirContext.
My component is sending out a mail and is setting up the InitialDirContext to get hold of the MX records. The code runs just fine when run as a main, i.e. the creation with property java.naming.factory.initial set to com.sun.jndi.dns.DnsContextFactory works just fine.
public static void main(String[] args) {
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
try {
InitialDirContext initialDirContext = new InitialDirContext(env);
Attributes attrs = initialDirContext.getAttributes("gmail.com", new String[]{"MX"});
Attribute attr = attrs.get("MX");
Set<String> hostNames = new HashSet<>();
if (attr != null) {
for (int i = 0; i < attr.size(); i++) {
String mxAttr = (String) attr.get(i);
String[] parts = mxAttr.split(" ");
hostNames.add(parts[1].substring(0, parts[1].length() - 1));
addIpAddresses(initialDirContext, parts[1], hostNames);
}
}
System.out.println("hostNames = " + hostNames.stream().sorted().collect(Collectors.joining(", ")));
} catch (NamingException e) {
e.printStackTrace(System.err);
}
}
However, when I run this type of code inside Felix I am getting the exception:
Caused by: javax.naming.NoInitialContextException: Cannot instantiate class: com.sun.jndi.dns.DnsContextFactory [Root exception is java.lang.IllegalAccessException: class javax.naming.spi.NamingManager (in module java.naming) cannot access class com.sun.jndi.dns.DnsContextFactory (in module jdk.naming.dns) because module jdk.naming.dns does not export com.sun.jndi.dns to module java.naming]
at java.naming/javax.naming.spi.NamingManager.getFactory(NamingManager.java:749)
at java.naming/javax.naming.spi.NamingManager.lambda$getInitialContext$1(NamingManager.java:711)
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:329)
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:205)
at java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:711)
at java.naming/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
at java.naming/javax.naming.InitialContext.init(InitialContext.java:236)
at java.naming/javax.naming.InitialContext.<init>(InitialContext.java:208)
at java.naming/javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:130)
I can see that the jdk.naming.dns module does not actually export the package com.sun.jndi.dns, but then how is it possible that the code works in a main class? Is there perhaps an additional setting that I need to add to my Felix config.properties file?

Spring Batch Java configuration - Writing to remote sftp xml file without local file

I have a requirement to write xml file to a sftp server in a Spring Batch application. Currently below code writes xml file to local file system using StaxEventItemWriter. I need to write directly to remote server instead of writing it to local and then moving to the sftp server. Referred this link (Writing to a remote file using Spring Integrations Sftp Streaming java configuration) but not sure how to write using StaxEventItemWriter/setup Resource object with remote file
public void write(List<? extends UserDTO> items) throws Exception {
for(UserDTO item : items) {
StaxEventItemWriter<UserDTO> staxWriter = getStaxEventItemWriter(item);
staxWriter.write(Arrays.asList(item));
}
}
private StaxEventItemWriter<UserDTO> getStaxEventItemWriter(UserDTO user) {
String key = user.getDomain();
StaxEventItemWriter<UserDTO> writer = writers.get(key);
if (writer == null) {enter code here
writer = new StaxEventItemWriter<>();
try {
UrlResource resource = new UrlResource("file:"+outputDir+"/"+key+"_"+fileName+".xml");
writer.setResource(resource);
writer.setRootTagName("customerSet");
Jaxb2Marshaller UserMarshaller = new Jaxb2Marshaller();
UserMarshaller.setClassesToBeBound(UserDTO.class);
writer.setMarshaller(UserMarshaller);
writer.setOverwriteOutput(Boolean.TRUE);
writer.open(executionContext);
} catch (MalformedURLException e) {
e.printStackTrace();
}
writers.put(key, writer);
}
return writer;
}
You can probably try to use SftpResource which is based on Spring Integration (similar to the solution in the link you shared) and use it in your StaxEventItemWriter.

How to set path (path.home) in elastic search by node Client (not by transport)

if(Constants.ELASTIC_NODE_CLIENT.equals(elasticClient)) {
File tempDir = null;
try {
//Settings settings = ImmutableSettings.settingsBuilder().put("script.inline", "on").build();
Settings.Builder builder = Settings.builder()
.put("path.data", ZephyrInitializer.getElasticsearchDataDirPath())
.put("script.disable_dynamic", "false")
.put("script.inline", "on")
.put("script.indexed", "on")
for(Object prop : props.keySet()) {
String key = prop.toString();
if(!key.equals("elastic.client") && key.startsWith("elastic.")) {
String elasticKey = key.split("elastic.")[1];
builder.put(elasticKey, props.getProperty(key));
}
}
if(elasticMaxClauseCount != null) {
if(StringUtils.isNumeric(elasticMaxClauseCount)) {
builder.put("index.query.bool.max_clause_count", Integer.valueOf(elasticMaxClauseCount));
}
}
Settings settings = builder.build();
node = new Node(settings);//.clusterName(elasticClusterName).node();
client = node.client();
logger.info("Bringing up elastic search in node mode" + client);
} catch (IOException e) {
e.printStackTrace();
}
if I am not setting path i.e. path.home I am getting error -
java.lang.IllegalStateException: path.home is not configured
if I am setting path.home by - .put("path.home", "D:\\elasticSearch\\elasticsearch-5.5.0\\bin"); -
I am getting error -
UnsatisfiedDependencyException: Error creating bean with name (but I
should not give local path) and if I am giving jar path location in
project like - .put("path.home",
"D:\ABC\z\web\target\web\WEB-INF\lib"); by doing this I am
getting same error - UnsatisfiedDependencyException: Error creating
bean with name
I spent a huge time looking into the jar code, viz. elasticsearch-2.4.4, org.elasticsearch.node.internal.InternalSettingsPreparer.prepareEnvironment() method. The exception comes while preparing the NodeClient with nodebuilder, nodeBuilder.local(true).settings(esSettings).node().client().The solution to this issue is providing the
-Des.default.path.home=/
in vm arguments. This is how the data node knows where it has to put the data. Whenever the "path.home" is not found, it is taken from vm arguments and the above property is referred.

How do you access .properties files inside an AppEngine app?

I've got an AppEngine app with two different instances, one for prod and one for staging. Accordingly, I'd like to configure the staging instance slightly differently, since it'll be used for testing. Disabling emails, talking to a different test backend for data, that kind of thing.
My first intuition was to use a .properties file, but I can't seem to get it to work. I'm using Gradle as a build system, so the file is saved in src/main/webapp/WEB-INF/staging.properties (and a matching production.properties next to it). I'm trying to access it like so:
public class Config {
private static Config sInstance = null;
private Properties mProperties;
public static Config getInstance() {
if (sInstance == null) {
sInstance = new Config();
}
return sInstance;
}
private Config() {
// Select properties filename.
String filename;
if (!STAGING) { // PRODUCTION SETTINGS
filename = "/WEB-INF/production.properties";
} else { // DEBUG SETTINGS
filename = "/WEB-INF/staging.properties";
}
// Get handle to file.
InputStream stream = this.getClass().getClassLoader().getResourceAsStream(filename);
if (stream == null) {
// --> Crashes here. <--
throw new ExceptionInInitializerError("Unable to open settings file: " + filename);
}
// Parse.
mProperties = new Properties();
try {
mProperties.load(stream);
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
The problem is that getResourceAsStream() is always returning null. I checked the build/exploded-app directory, and the .properties file shows up there. I also checked the .war file, and found the .properties file there as well.
I've also tried moving the file into /WEB-INF/classes, but that didn't make a difference either.
What am I missing here?
Try
BufferedReader reader = new BufferedReader(new FileReader(filename));
or
InputStream stream = this.getClass().getResourceAsStream(filename);

Categories