two versions of solr on tomcat - java

I have got installed two versions of solr on Tomcat 6, 1.3 and 4.7 each of them are accessible but in the tomcat configuration's tab Java -Dsolr.solr.home=C:\Solr\solr where this path is the path of 1.3 However, I have the 4.7 on E:\new-solr.
When I try to create new core it created well but it disappeared after restarting Tomcat. I belive that the missing of correct Solr home is the reason. So, is there a way to set multiple solr home in Java properties of Tomcat?
Edit: When I run Tomcat with -Dsolr.solr.home=C:\Solr\solr I have got errors about missing cores in Solr 4.7 version where those
cores works fine in Solr 1.3.
SolrCore Initialization Failures archive: org.apache.solr.common.SolrException:org.apache.solr.common.SolrException:
Could not load config file c:\solr\solr\archive\solrconfig.xml

Looks like you are passing in the value of solr home using JAVA_OPTS. You need to edit server.xml and add the appropriate Solr home to Context. The following example is from SolrTomcat page on the Solr wiki.
<Context docBase="/opt/solr/example/solr/solr.war" debug="0" crossContext="true">
<Environment name="solr/home" type="java.lang.String" value="/opt/solr/example/solr" override="true"/>
</Context>

Solr's SolrResourceLoader#locateSolrHome first tries JNDI and then system properties to find its settings. As -D system properties are shared between all applications in a single Tomcat instance, those cannot be used to configure multiple Solr instances.
If for some reason one cannot use JNDI (like <Environment name="solr/home" ...> in XML files), or a single instance with multiple cores, then one could wrap the Solr WAR into one's own application and use a servlet context listener to (temporarily) change the system properties while starting.
This surely is a hack, and relies on Tomcat not starting applications in parallel, and on Solr only reading the system properties on startup. I've tested this to work nicely, but still it's probably only suitable for testing purposes.
Again, this first of all needs one to wrap Solr into one's own application. Next, create a folder /some/config with a sub folder for each instance, matching its context name. In each sub folder create a custom.properties file:
# This file /some/config/[servlet-context-name]/custom.properties is used
# if Tomcat is started with:
# -Dcustom.config.dir=/some/config
# ...and then (temporarily) overwrites any system properties specified below:
solr.solr.home=/some/other/folder/conf
solr.data.dir=/some/other/folder/data
To merge system properties based on some key-values in a properties file:
/**
* Tries to find the given file and merges its properties into the existing
* system properties.
*
* #param configFile
* full path of a property file
* #return {#code true} if the file was found and merged; {#code false}
* otherwise
*/
private boolean mergeSystemProperties(final String configFile) {
try (final FileInputStream is = new FileInputStream(configFile)) {
final Properties custom = new Properties();
custom.load(is);
for (final Map.Entry<Object, Object> prop : custom.entrySet()) {
LOG.info("Setting {}={}", prop.getKey(), prop.getValue());
System.setProperty((String)prop.getKey(), (String)prop.getValue());
}
return true;
} catch (final FileNotFoundException e) {
LOG.info("Could not find custom properties: {}", configFile);
} catch (final IOException e) {
LOG.error("Failed to read custom properties: " + configFile, e);
}
return false;
}
This can be used in a listener:
public class TestConfigContextListener implements ServletContextListener {
private static final Logger LOG = ...
private static final String PROP_DIR = "custom.config.dir";
private static final String FILE_NAME = "custom.properties";
#Override
public void contextInitialized(final ServletContextEvent event) {
final String configDir = System.getProperty(PROP_DIR);
if (configDir == null) {
LOG.info("No value for -D{}; not reading custom config", PROP_DIR);
} else {
LOG.info("Custom config dir: -D{}={}", PROP_DIR, configDir);
final ServletContext context = event.getServletContext();
// Either "" for the root, or "/some-path" otherwise
final String contextPath = context.getContextPath();
if (!contextPath.isEmpty()) {
if (mergeSystemProperties(configDir + File.separator
+ contextPath.substring(1, contextPath.length())
+ File.separator + FILE_NAME)) {
// We found the configuration in a subfolder matching the
// specific contextPath; done.
return;
}
}
// Root context, or no configuration in a subfolder matching the
// specific contextPath; try to load from configDir itself:
mergeSystemProperties(configDir + File.separator + FILE_NAME);
}
}
...
}
...with in web.xml:
<!--
Tries to read a property file to set/override system properties just before
Solr is initialized, sort of allowing to run multiple instances with
different settings, IF THEY ARE NOT STARTED SIMULTANEOUSLY.
-->
<listener>
<listener-class>net.example.TestConfigContextListener</listener-class>
</listener>
Final notes: though one could use <env-entry> in web.xml for "fake" JNDI entries, using ServletContext#setInitParameter to change those in the context listener has no effect. Also, the JNDI context java:comp/env is read-only hence cannot be changed from code. So one really needs to fall back to (temporarily) setting the system properties.

Related

Maven project - load file from outside of resources folder (project root)

I am creating a contacts application using Maven in Netbeans. For the operation of the program I want users to add and store images (contact avatars) in a folder /avatars and access them on a listener event. I can access images from within the ProjectRoot/src/main/resources/images directory, but cannot access ProjectRoot/avatars. Note: I do not want to store avatars in the resources directory because these will be user-added during the programs operation.
I have tried using getClass().getResource(avatarPath); as suggested in similar questions, but it has not worked. I have also tried adding the "avatars" directory to the POM as its own resource directory, but that has not worked either.
How can I access files/folders in the root directory of my project when using Maven?
listviewContacts.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Contact>() {
#Override
public void changed(ObservableValue<? extends Contact> observable, Contact oldValue, Contact newValue) {
String avatar = newValue.getAvatar();
String avatarPath = null;
if (avatar.isEmpty()) {
avatarPath = "/images/" + DEFAULT_AVATAR; // loads from ProjectRoot/src/main/resources/images
} else {
avatarPath = "/avatars/" + avatar; // won't load from ProjectRoot/avatars
}
try {
imageviewContact.setImage(new Image(avatarPath));
} catch (IllegalArgumentException ex) {
System.err.println("Could not locate " + avatarPath);
}
}
});
You are mixing 2 different things.
You can either have a classpath resource packed in jarfile along with your classes, or in a directory that is explicitly added java to java classpath(using java -cp commandline argument). That can be accessed via getClass().getResource.
Or you can load a file from arbitrary location, using java.io.File. Then your "projectRoot" is some folder in a filesystem, that you can either hardcode, configure by -DprojectRoot=C:/fun/with/files, or use some of relative paths.
Maven has nothing to do with it, as avatars "will be will be user-added during the programs operation".
Your users will not launch your IDE, right ?
The problem was in understanding where the different constructors of javafx.scene.image.Image begin their path.
When using the URL constructor for Image, the URL path will start in Maven's defined resources folder (/src/main/resources or whatever additional resource directories were added to the pom.xml file):
// the supplied string invokes the URL constructor
Image image = new Image("path/to/file");
When using the InputStream constructor for Image (via FileInputStream), the path will start at the root directory of the project/application:
// the FileInputStream invokes the InputStream constructor
Image image = new Image(new FileInputStream("path/to/file"));

Application Insights in Cuba Platform

I'm trying to use Azure Application Insight in Cuba Platform: https://learn.microsoft.com/en-us/azure/application-insights/app-insights-java-get-started
I managed to add the library to Cuba Platform, in particular to the Web module, but I couldn't set the "Instrumentation key" in any way.
There are three ways to do so:
1- Putting ApplicationInsights.xml in the "resource" folder
I couldn't find a place to put the file to be read by TelemetryConfigurationFactory class. Internally, I see it's using getResource() to scan in various "sensible" places.
I tried WEB-INF, META-INF, conf directory in Tomcat, conf/app, root of java package, work/app in Tomcat and probably something more with no results.
2- System property: -DAPPLICATION_INSIGHTS_IKEY=your_ikey
3- Environment variable: APPLICATION_INSIGHTS_IKEY
Tried both in a docker container, tried the last one locally: no results. In particular, System.getEnv is returning null even after exporting manually the variable locally, so this could be some error on my side
Any insight :D is welcome
I tried to search for the configuration of Instrumentation key from Application Insights source code.
I can see the snippet of code as below in the TelemetryConfigurationFactory Class.
/**
* Setting an instrumentation key:
* First we try the system property '-DAPPLICATION_INSIGHTS_IKEY=i_key' or '-DAPPINSIGHTS_INSTRUMENTATIONKEY=i_key'
* Next we will try the environment variable 'APPLICATION_INSIGHTS_IKEY' or 'APPINSIGHTS_INSTRUMENTATIONKEY'
* Next we will try to fetch the i-key from the ApplicationInsights.xml
* #param userConfiguration The configuration that was represents the user's configuration in ApplicationInsights.xml.
* #param configuration The configuration class.
*/
private void setInstrumentationKey(ApplicationInsightsXmlConfiguration userConfiguration, TelemetryConfiguration configuration) {
try {
String ikey;
// First, check whether an i-key was provided as a java system property i.e. '-DAPPLICATION_INSIGHTS_IKEY=i_key', or '-DAPPINSIGHTS_INSTRUMENTATIONKEY=i_key'
ikey = System.getProperty(EXTERNAL_PROPERTY_IKEY_NAME);
if (!Strings.isNullOrEmpty(ikey)) {
configuration.setInstrumentationKey(ikey);
return;
}
ikey = System.getProperty(EXTERNAL_PROPERTY_IKEY_NAME_SECONDARY);
if (!Strings.isNullOrEmpty(ikey)) {
configuration.setInstrumentationKey(ikey);
return;
}
// Second, try to find the i-key as an environment variable 'APPLICATION_INSIGHTS_IKEY' or 'APPINSIGHTS_INSTRUMENTATIONKEY'
ikey = System.getenv(EXTERNAL_PROPERTY_IKEY_NAME);
if (!Strings.isNullOrEmpty(ikey)) {
configuration.setInstrumentationKey(ikey);
return;
}
ikey = System.getenv(EXTERNAL_PROPERTY_IKEY_NAME_SECONDARY);
if (!Strings.isNullOrEmpty(ikey)) {
configuration.setInstrumentationKey(ikey);
return;
}
// Else, try to find the i-key in ApplicationInsights.xml
if (userConfiguration != null) {
ikey = userConfiguration.getInstrumentationKey();
if (ikey == null) {
return;
}
ikey = ikey.trim();
if (ikey.length() == 0) {
return;
}
configuration.setInstrumentationKey(ikey);
}
} catch (Exception e) {
InternalLogger.INSTANCE.error("Failed to set instrumentation key: '%s'", e.getMessage());
}
}
It seems that Instrumentation key can be configured as a java system property or as an environment variable or in ApplicationInsights.xml.
According to your description , System.getEnv("XXX") in your code return null.
You could check the possible reasons below :
Use My Computer > Advanced > Environment Variables to make a variable visible to all new processes.
2.The process which tries to read the variable is already running. Restart it.
3.The start script of Tomcat unsets the variable before it invokes java.exe
4.Tomcat unsets the variable in it's Java code.
In addition , you could refer to this thread : System.getenv() returns null when the environment variable exists.
Hope it helps you.

ResourceBundle is unable to load properties file from package inside a webapp

I am working on refactoring a huge collection of code in an enterprise-scaled application.
The first step I want to take is to localize the log messages, so I decided to use the StringManager that I saw when I was reading the source code of Apache Tomcat.
The basic idea is to declare a file named LocalString.properties in the packages and define log messages in them. So in a way, this localizes the Strings to scope of that package only, so that it looks like:
Application
`----src
| `----main
| `----java
| `----package
| `----BusinessAction.java
| `----LocalStrings.properties
`----pom.xml
And an object of this StringManager is instantiated as:
private static final StringManager sm = StringManager.getManager("package");
This is constructor of the StringManager class.
/**
* Creates a new StringManager for a given package. This is a
* private method and all access to it is arbitrated by the
* static getManager method call so that only one StringManager
* per package will be created.
*
* #param packageName Name of package to create StringManager for.
*/
private StringManager(String packageName) {
String bundleName = packageName + ".LocalStrings";
try {
bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
} catch( MissingResourceException ex ) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if( cl != null ) {
try {
bundle = ResourceBundle.getBundle(
bundleName, Locale.getDefault(), cl);
} catch(MissingResourceException ex2) {
// Ignore
}
}
}
// Get the actual locale, which may be different from the requested one
if (bundle != null) {
locale = bundle.getLocale();
}
}
This works absolutely fine when used in a standalone application, but is causing issues when used in a web application.
I don't understand why the bundle fails to load on the first hand, but in the catch block, I can definitely tell that it is because the classloader is an instance of WebappClassloader.
What mistake I am making here? Also, what would be the good ways to load this property file?
Edit
The problem here is with the Maven build. Maven process all resources in src/main/resources and ignores the ones in src/main/java. So in the end, the compiled application did't had the LocalStrins.properties file where it was supposed to be.
Solved it by creating package in src/main/resources and putting the file in there.
The reason it fails is simply that the LocalStrings.properties file is not in your war file. In a Maven project, resources are supposed to be under src/main/resources. Not src/main/java. Maven will simply ignore resources under src/main/java, so they won't be in the built webapp at all, and thus won't be available at runtime.

Infinite scan for fonts in Apache FOP on CentOS

I use Apache Batik to convert SVG into PDF in one of the projects. The project is Spring application running in Tomcat 7. Everything works OK on development machine which runs under Ubuntu with Tomcat being started using $CATALINA_HOME/bin/startup.sh. But when I try to run the app on production server with CentOS 6 and Tomcat started using service tomcat7 start command the app falls into infinite loop on convertation. I've tried to debug the problem and found this piece of code:
/**
* Creates the {#link FontInfo} instance for the given configuration.
* #param cfg the configuration
* #param useComplexScriptFeatures true if complex script features enabled
* #return the font collection
* #throws FOPException if an error occurs while setting up the fonts
*/
public static FontInfo createFontInfo(Configuration cfg, boolean useComplexScriptFeatures)
throws FOPException {
FontInfo fontInfo = new FontInfo();
final boolean strict = false;
if (cfg != null) {
URI thisUri = new File(".").getAbsoluteFile().toURI();
InternalResourceResolver resourceResolver
= ResourceResolverFactory.createDefaultInternalResourceResolver(thisUri);
//TODO The following could be optimized by retaining the FontManager somewhere
FontManager fontManager = new FontManager(resourceResolver, FontDetectorFactory.createDefault(),
FontCacheManagerFactory.createDefault());
//TODO Make use of fontBaseURL, font substitution and referencing configuration
//Requires a change to the expected configuration layout
DefaultFontConfig.DefaultFontConfigParser parser
= new DefaultFontConfig.DefaultFontConfigParser();
DefaultFontConfig fontInfoConfig = parser.parse(cfg, strict);
DefaultFontConfigurator fontInfoConfigurator
= new DefaultFontConfigurator(fontManager, null, strict);
List<EmbedFontInfo> fontInfoList = fontInfoConfigurator.configure(fontInfoConfig);
fontManager.saveCache();
FontSetup.setup(fontInfo, fontInfoList, resourceResolver, useComplexScriptFeatures);
} else {
FontSetup.setup(fontInfo, useComplexScriptFeatures);
}
return fontInfo;
}
in PDFDocumentGraphics2DConfigurator class. When I'm running the app on developer machine the line URI thisUri = new File(".").getAbsoluteFile().toURI(); results with thisUri being assigned with ~/tomcat/bin/. folder. When the app is running on production machine it is assigned with /. value. I think that this is the main problem because the value of thisUri is the folder in which FOP starts fonts search and on the production machine this is the root of file system and recursive search on the whole FS structure is very slow. I tried to add fop.xconf file to the WEB-INF directory with fonts configuration but it didn't affected the behavior of FOP. And I can't start Tomcat on production server the same way as I start on the dev machine.
Has anyone ideas on how to configure the base directory for font scan of FOR? Or am I doing something wrong?
I've found the workaround for the problem. I'm not sure if its wright or wrong to do stuff like that but it works. The workaround is based on the fact that File.getAbsolutFile() by default returns the directory resolved against the directory defined by user.dir option. So I need some way to pass this option on Tomcat service start. The only way I've found to do this is to add -Duser.dir=/%CATALINA_HOME/ to the CATALINA_OPTS variable defined in %CATALINA_HOME/bin/setenv.sh file. After that the font scan process took normal amount of time and my app started to work fine.

Embeded Tomcat with webapp directory within the classpath/jar

So I have a Java application that use to be packaged as a war and then deployed to Tomcat, but now I have it setup so it all runs straight from a jar file using embedded Jetty as follows:
class JettyServer extends ServerTrait {
val server = new Server()
val connector = new ServerConnector(server)
connector.setPort(BigSenseServer.config.options("httpPort").toInt)
server.setConnectors(Array(connector))
val context = new ServletContextHandler()
context.setContextPath(BigSenseServer.webRoot)
context.addServlet(new MasterServlet().getClass, "/*")
context.addEventListener(new InitLoggingListener())
context.addEventListener(new DBUpdateListener())
val fileContext = new WebAppContext()
fileContext.setContextPath(BigSenseServer.contentRoot)
fileContext.setResourceBase(BigSenseServer.getClass.getResource("/io/bigsense/web").toExternalForm)
val handlers = new HandlerCollection()
handlers.setHandlers(Array( fileContext, context, new DefaultHandler()))
server.setHandler(handlers)
override def startServer() {
server.start
server.join
}
override def stopServer() {
server.stop
}
}
The webroot is /bigsense/api and the contentRoot is /static. In this configuration, static files like CSS and Javascript are served from the /io/bigsense/web package (kept in src/main/resources in SBT). In my original, the context-root was /bigsense and the servlet was mapped to api/*, so all the static content could be served directly from /bigsense/{js,css,whatever}.
I couldn't figure out how to get Jetty to do the same thing, but the current setup listed above works fine and I adjusted all my templates to get that static path from the same config object (which has a backend in a property file).
I want to create an embedded Tomcat implementation as well and I've read several guides, but they all seem to want a real webapp base directory. I can't find any examples which either just map a servlet directory without a webapp base or take the webapp base from the classpath (in a jar) instead of a real physical directory. I've tried things similar to the following:
EDIT Got the servlet working with the following. Now I just need the ServletContextListneres and a way to server files from the jar:
class TomcatServer extends ServerTrait {
val tomcat = new Tomcat()
tomcat.setPort(BigSenseServer.config.options("httpPort").toInt)
val tmp = new File(System.getProperty("java.io.tmpdir"))
val ctx = tomcat.addContext(BigSenseServer.webRoot,tmp.getAbsolutePath)
Tomcat.addServlet(ctx,"bigsense",new MasterServlet())
ctx.addServletMapping("/*","bigsense")
override def startServer() = {
tomcat.start()
tomcat.getServer().await()
}
override def stopServer() = tomcat.stop
}
So I have a similar setup to Jetty for the main servlet. I can't find any functions on the context object for adding in the two ServletContextListner objects I have. I also need to be able to serve my static context from the jar on contentRoot (/static).

Categories