Infinite scan for fonts in Apache FOP on CentOS - java

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.

Related

java rmi simple project classNotFoundException binding registry

Ok, I'm sure this should be pretty easy, but I'm fairly new to Java (I'm more a .NET boy :P) and after following every single recommendation I found here to no success, I think it's time to step back and ask.
I'm trying to start a simple rmi project with a client, a server and a common project where common interfaces are defined. I've just implemented my server code, and when I try to run it to check if everything is fine, I get struck on a java.lang.ClassNotFoundException.
After following several answers on similar issues, I'm fair sure that my problem comes from rmiregistry running on a different location than my project.
I use following code to set registry codebase:
public class Utils {
public static final String CODEBASE = "java.rmi.server.codebase";
public static void setCodeBase(Class<?> c) {
String ruta = c.getProtectionDomain().getCodeSource().getLocation().toString();
String path = System.getProperty(CODEBASE);
if (path != null && !path.isEmpty()) {
ruta = path + " " + ruta;
}
System.setProperty(CODEBASE, ruta);
}
}
Then, I try to start my server code with this main class:
public class MainRegulador {
public static void main(String[] args) throws AccessException, RemoteException, NotBoundException {
Utils.setCodeBase(IRegulador.class);
Registry registro = null;
Remote proxy = null;
try {
Regulador myReg = new Regulador();
proxy = UnicastRemoteObject.exportObject(myReg, 36510);
registro = LocateRegistry.getRegistry();
registro.rebind("Distribuidor", proxy); //this is the line where exception is thrown
System.out.println("El Regulador está corriendo. Pulse ENTER para finalizar el proceso.");
System.in.read();
} catch(Exception ex) {
System.out.println("No se ha logrado inicializar el Registrador");
System.out.println(ex.getMessage());
} finally {
if (registro != null && proxy != null) {
registro.unbind("Distribuidor");
UnicastRemoteObject.unexportObject(proxy, true);
}
}
}
}
But when I run it, always get a java.lang.ClassNotFoundException at IRegulador interface.
Now the fun part:
I've printed to console java.rmi.server.codebase value, and it's pointing to bin folder of project where IRegulador interface is defined. (file:/F:/Practicas%20y%20dem%c3%a1s/Sistemas%20Distribuidos/common/bin/)
Obviously, that project is also set in the classpath of server project
(Regulador)
Workspace and rmiregistry are on different disks
Despite all, it doesn't seem a global classpath problem, as Utils class is on the same project as IRegulador interface, and it runs before the exception is thrown (as java.rmi.server.codebase is correctly set).
I've tried to set the classpath of rmiregistry before calling it (although it is directly discouraged on some answers), but nothing changed.
I've also tried to start rmiregistry.exe from Regulador project bin folder, but also seemed to don't change anything.
Coming from a .NET background, I've always found these classpath issues confusing, and this one is starting to consume much more time than I suspect it deserves. I'm in desperate need of help.
UPDATE: I'm starting to think that the problem is within the url it's passed to the codebase from IRegulador.class. If I paste it into windows explorer, the SO is unable to locate it, so I supose that it's being built with some structure problem that prevents the registry to reach the route:
file:/F:/Practicas%20y%20dem%c3%a1s/Sistemas%20Distribuidos/common/bin/
UPDATE2: I thought path route could be too complex, so I decided to simplify it and strip it from any non-straight character. Now codebase value is
file:/F:/Practicas/SD/common/bin/
However the problem persists, I don't know why rmiregistry is unable to reach that folder.
Then I decided to move the whole project to the same disk where rmiregistry is executed, and see if it changes anything. But nothing changed, same problem.
Ok, finally I got it working...
I've just copied rmiregistry.exe into the common/bin folder and launch it directly from there (previously just had called from there).
This seems to fix the problem with the routes (actually it makes the route available to the registry as it's on the same folder, probably all my codebase writting code is superflous now).

Is it possible to pass JVM arguments to a Jenkins 2.0 build?

I have a Java app that retrieves username/password creds from a resource property file.
For obvious reasons, I don't include the actual username/password values when I commit to SVN. I just make sure they're replaced with bogus values before committing.
Now I'm wanting to build my app on a remote Jenkins 2.0 box, however, since the values being stored in SVN are bogus, when Jenkins checks out my code and runs my integration tests, they fail because they can't authenticate when using the bogus values.
I was thinking maybe I could add some logic to my application that will first try to retrieve the username/password creds via a System.getProperty() and if those properties don't exist, then try looking at the resource file.
So, is it possible with Jenkins 2.0 to pass an argument to the JVM during a build so that a System.getProperty() would work?
You can do this using Jenkins Pipeline with declarative syntax:
Jenkinsfile:
pipeline {
agent {
label 'master'
}
environment {
//foo var
foo = "Hello !";
}
stages {
stage("test-var") {
steps {
// If you are using LINUX use EXPORT
bat "set foo=\"${env.foo}\""
bat "java -jar /someplace/DummyMain.jar"
}
}
}
}
Please notice I am using: System.getenv("foo"); instead of getProperty
Java Class:
/**
*
* #author daniel
*/
public class DummyMain {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
String property = System.getenv("foo");
System.out.println(property);
}
}
You will get: Hello ! when you run your Pipeline. If you are more familiar with Script Groovy syntax instead of Pipeline Declarative Syntax should not be a problem.
Just write the logic for read the Property File and you are set !

GAE Datastore - cannot start LocalDevelopmentDatastore programmatically on Windows

Environment:
Java API google-api-services-datastore-protobuf v1beta2-rev1-3.0.0.
OS: Windows 7.
Goal:
Start Local Datastore Server using the method:
public void start(String sdkPath, String dataset, String cmdLineOptions)
from com.google.api.services.datastore.client.LocalDevelopmentDatastore.java in order to use it in unit tests.
Steps:
I downloaded gcd tool gcd-v1beta2-rev1-3.0.2.zip and put it to C:\gcd folder
(paths to gcd.cmd and gcd.sh are `C:\gcd).
Also, I set environment variables:
"DATASTORE_HOST"="http://localhost:8080" and
"DATASTORE_DATASET"="myapp".
Problem:
LocalDevelopmentDatastoreException occurs.
Caused by: java.io.IOException: Cannot run program "./gcd.sh" (in directory "C:\gcd"): CreateProcess error=2, The system cannot find the file specified.
Note that it tries to find ./gcd.sh but not gcd.cmd.
Java code:
String datasetName = "myapp";
String hostName = "http://localhost:8080";
DatastoreOptions options = new DatastoreOptions.Builder()
.host(hostName)
.dataset(datasetName).build();
LocalDevelopmentDatastoreOptions localOptions = new LocalDevelopmentDatastoreOptions.Builder()
.addEnvVar("DATASTORE_HOST", hostName)
.addEnvVar("DATASTORE_DATASET", datasetName).build();
LocalDevelopmentDatastore datastore = LocalDevelopmentDatastoreFactory.get().create(options, localOptions);
datastore.start("C:\\gcd", datasetName);
This code is based on the example from LocalDevelopmentDatastore.java documentation.
Please help.
It seems as though the method is only programmed to look for gcd.sh, as it doesn't appear there's anything in your config which could have helped this to not fail. I suggest you open a defect report in the Cloud Platform Public Issue Tracker.
Did you consider gcloud-java for using the Datastore?
It also has an option for programmatically starting the local datastore using LocalGcdHelper which should work on Windows.

Detect Play 2.2.x mode prior to start of Application using Java

I want to point my play application to a particular application config file based on the environment it is running in. There are three and they correspond to the standard Play states:
application.dev.conf
application.test.conf
application.prod.conf
A co-worker shared a method for doing this which requires setting an OS environment variable.
I'd like to eliminate the need to set an OS variable.
My preference is the use whatever Play uses at startup to know what mode it is in.
For example, if you execute play run from the command line, part of the output is "[info] play - Application started (Dev)"
I want to use this information in my Global.java where I override onLoadConfig like so:
public Configuration onLoadConfig(Configuration baseConfiguration, File f, ClassLoader loader) {
String playEnv=<some static method to get mode>;
Config additionalConfig = ConfigFactory.parseFile(new File(f,"conf/application."+playEnv+".conf"));
Config baseConfig = baseConfiguration.getWrappedConfiguration().underlying();
return new Configuration(baseConfig.withFallback(additionalConfig));
}
Everything that I find is how to do this after the application has been started i.e. using isDev(), isTest(), isProd().
Is there static method that provides the mode while I am overriding onLoadConfig in Global.java?
I think play run is dev, play start is prod.
EDIT: If you're looking to see what the current mode is, it's passed in through play.api.Play.current:
Play.current.mode match {
case Play.Mode.Dev => "dev"
case Play.Mode.Prod => "prod"
}
The issue appeared to be addressed in the latest Play (3.0.0). There is another onLoadConfig method added to Global witch has a mode: {Dev,Prod,Test} parameter.
public Configuration onLoadConfig(Configuration config, File path, ClassLoader classloader, Mode mode) {
return onLoadConfig(config, path, classloader); // default implementation
}
Play allows to specifying alternative configuration file with command line so no need for setting OS variables.
You can of course create some bash script / bat file to avoid writing it every time

Apache Tomcat Cataline file changes not reflecting!

I am using apache-tomcat-6.0.18 on windows xp prefossional SP3.
My requirement is to show additional information ( like Organization Name) in the Tomcat Manager => Server Status => in between the JVM and http- Header. I have modified the file "org.apache.catalina.manager.StatusTransformer::writeConnectorState<method name>" from catalina.jar source and added simple text to it. Sample code is
public static void writeConnectorState(PrintWriter writer, ObjectName tpName, String name, MBeanServer mBeanServer, Vector globalRequestProcessors, Vector requestProcessors, int mode)throws Exception{
if (mode == 0) {
// START - Added New Code to display org name
writer.print("<h1>");
writer.print("XYZ Organization.");
writer.print("</h1>");
// END - Added New Code to display org name
writer.print("<h1>");
writer.print(name);
writer.print("</h1>");
writer.print("<p>");
writer.print(" Max threads: ");
writer.print(mBeanServer.getAttribute(tpName, "maxThreads"));
writer.print(" Current thread count: ");
writer.print(mBeanServer.getAttribute(tpName, "currentThreadCount"));
writer.print(" Current thread busy: ");
writer.print(mBeanServer.getAttribute(tpName, "currentThreadsBusy"));
...........
...........
}else{
.........
}// end if-else }// method end
Again created catalina.jar with modified code. and replaced with the existing jar from catalina_home/bin. Restarted the tomcat but nothing coming out of it.
Even if i remove catalina.jar from catalina_home/bin and starts the tomcat, its working!!!!
I tried even after restarting the system but my changes are not reflecting.
Please help me out for the following queries
Am i modifying the wrong file?
How tomcat is running without catalina.jar?
How to reflect the changes? i.e. Any other way?
Not 100% sure on this, but I think you should place the modified catalina.jar in catalina_home/lib, as I believe that's where the web-applications load their shared libraries (Tomcat Manager is just another app under catalina_home/webapps/).
Edit: I checked one of our servers, there's no catalina.jar under catalina_home/bin, only under catalina_home/lib.

Categories