Hibernate configure file - java

Let say I have the follow code.
private static String configFile = null;
File cf = new File(configFile);
Configuration c = new Configuration();
if (cf.exists() && cf.isFile()) {
c.configure(cf);
} else {
c.configure(configFile);
}
I am wondering what is the difference between c.configure(cf) and c.configure(configFile). In my code,configFile is repsented as resource and cf is the the configFile object.
I found these two from this (api).
public Configuration configure(String resource)
throws HibernateException
public Configuration configure(File configFile)
throws HibernateException

The documentation of the API isn't explicitly clear, is it?
I tracked it as far as this class before getting fed up:
https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/boot/cfgxml/internal/ConfigLoader.java
But it looks like in case of configure(String resource), it is the name of a resource as would be passed to the Java class loader to get a resource as a stream, i.e.:
http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getResourceAsStream(java.lang.String)
Whereas, configure(File configFile), it uses a FileInputStream.
In either case Hibernate is still expecting the same XML format for the configuration.

Related

How to read war-file manifest in its jar-dependency?

How do I read the war-file manifest property in its jar-dependency?
UPD: servlets are not used here (it's spring-bean initialization code).
Since a .war file’s purpose is to handle servlets, I assume all of your code is called from servlets, or from a technology built on servlets, like JSP, JSF, or even Spring.
Call the current request’s getServletContext() method, and use the getResource or getResourceAsStream method of ServletContext. Those methods work just like the same methods of java.lang.Class, only they look in the .war file itself before searching the web application’s classpath for a matching path.
For example:
public Optional<Manifest> getWarManifest(ServletRequest request)
throws IOException {
InputStream manifest =
request.getServletContext().getResourceAsStream(
"/META-INF/MANIFEST.MF");
if (manifest == null) {
return Optional.empty();
}
try (InputStream stream = new BufferedInputStream(manifest)) {
return Optional.of(new Manifest(stream));
}
}
Update:
Since you want to read the manifest when preparing a Spring bean, it appears you can autowire a ServletContext object:
#Configuration
public class MyAppConfig {
#Bean
public MyBean createMyBean(#Autowired ServletContext context)
throws IOException {
Optional<Manifest> manifest;
InputStream source =
context.getResourceAsStream("/META-INF/MANIFEST.MF");
if (source == null) {
manifest = Optional.empty();
} else {
try (InputStream stream = new BufferedInputStream(source)) {
manifest = Optional.of(new Manifest(stream));
}
}
return new MyBean(manifest);
}
}

add directory to classpath in runtime

In my current spring project, when I run the application, it's created a directory on the user's home directory where I store some configuration files (*.properties file). In my code, I refer to this file in that way:
private String getFilename() {
return System.getProperty("user.home")+File.separator+".webapp"+File.separator+"webapp.preferences";
}
which allows me run the application in any operational system without change the code. I need add this directory to the classpath of the application, to allow me use the annotation PropertySource to access the properties stored in the file using either the method getproperty from Enviroment class or the Value annotation.
I using spring-boot, so the start point for the application it's that:
#Controller
#EnableJpaRepositories
#EnableAutoConfiguration
#ComponentScan(value="com.spring")
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
I also have classes WebAppInitializer, WebAppConfig and DispatcherConfig to store the configurations handled by the XML files web.xml and dispatcher-config.xml from spring.
Anyone can tell if this is possible and hor to accomplish that?
UPDATE
Following the sugestions in the commentaries, I add to my project this bean:
#Bean
static PropertySourcesPlaceholderConfigurer property() throws Exception {
PropertySourcesPlaceholderConfigurer propertyConfigurer = new PropertySourcesPlaceholderConfigurer();
String filename = System.getProperty("user.home")+File.separator+".webapp"+File.separator+"webapp.preferences";
File file = new File( filename );
if(file.exists())
propertyConfigurer.setLocation( new FileSystemResource( filename ) );
else {
if(file.mkdir()) {
FileOutputStream fos = new FileOutputStream( filename );
fos.close();
propertyConfigurer.setLocation( new FileSystemResource( filename ) );
}
}
return propertyConfigurer;
}
and try use this in my pojo class:
#Input(label = "Titulo")
#Property(key = "geral.titulo")
#Value(value = "${geral.titulo}")
private String titulo;
but when I create a new instance of this classe, the fields don't receive the value indicated by the annotation. What I am doing wrong? I verify the file and the properties exists in it.

Mule - testing a flow that has an inbound/outbound endpoint with a Mule property as the file path

I'm trying to write a test for a Mule flow that will involve dropping a file in a location, waiting for it to be processed by my flow and compare the output to see if it has been transformed correctly. My flow looks as follows:
<flow name="mainFlow" processingStrategy="synchronous">
<file:inbound-endpoint name="fileIn" path="${inboundPath}">
<file:filename-regex-filter pattern="myFile.csv" caseSensitive="true"/>
</file:inbound-endpoint>
...
<file:outbound-endpoint path="${outboundPath}" outputPattern="out.csv"/>
</flow>
Is there a way I can access the inboundPath and outboundPath Mule properties inside of my test class so that I can drop files and wait for output in the correct places?
The test class I'm using is:
public class MappingTest extends BaseFileToFileFunctionalTest {
#Override
protected String getConfigResources() {
return "mappingtest.xml";
}
#Test
public void testMapping() throws Exception {
dropInputFileIntoPlace("myFile.csv");
waitForOutputFile("out.csv", 100);
assertEquals(getExpectedOutputFile("expected-out.csv"), getActualOutputFile("out.csv"));
}
}
Which extends this class:
public abstract class BaseFileToFileFunctionalTest extends FunctionalTestCase {
private static final File INPUT_DIR = new File("/tmp/muletest/input");
private static final File OUTPUT_DIR = new File("/tmp/muletest/output");
private static final Charset CHARSET = Charsets.UTF_8;
#Before
public void setup() {
new File("/tmp/muletest/input").mkdirs();
new File("/tmp/muletest/output").mkdirs();
empty(INPUT_DIR);
empty(OUTPUT_DIR);
}
private void empty(File inputDir) {
for (File file : inputDir.listFiles()) {
file.delete();
}
}
protected File waitForOutputFile(String expectedFileName, int retryAttempts) throws InterruptedException {
boolean polling = true;
int attemptsRemaining = retryAttempts;
File outputFile = new File(OUTPUT_DIR, expectedFileName);
while (polling) {
Thread.sleep(100L);
if (outputFile.exists()) {
polling = false;
}
if (attemptsRemaining == 0) {
VisibleAssertions.fail("Output file did not appear within expected time");
}
attemptsRemaining--;
}
outputFile.deleteOnExit();
return outputFile;
}
protected void dropInputFileIntoPlace(String inputFileResourceName) throws IOException {
File inputFile = new File(INPUT_DIR, inputFileResourceName);
Files.copy(Resources.newInputStreamSupplier(Resources.getResource(inputFileResourceName)), inputFile);
inputFile.deleteOnExit();
}
protected String getActualOutputFile(String outputFileName) throws IOException {
File outputFile = new File(OUTPUT_DIR, outputFileName);
return Files.toString(outputFile, CHARSET);
}
protected String getExpectedOutputFile(String resourceName) throws IOException {
return Resources.toString(Resources.getResource(resourceName), CHARSET);
}
}
As you can see I'm currently creating temporary input/output directories. I'd like to make this part read from the Mule properties if possible? Thanks in advance.
After observing your test classes and code I could see that you want to dynamically create temp folders place files in them. And the flow should read the files from Temp Directory and write output to another Temp directory. Point to be noted is that Mule's Endpoints are created when the configuration is loaded. So the ${inbound} and ${outbound} should be provided to the mule flow by the time they are provided.
So one option can be to create a dummy flow pointing to the temp folders for testing.
or
Create a test properties file pointing to the temp folders and load that to your flow config, so that your flow endpoints will get the temp folder paths.
In any way path cannot be provided to the flow inbound endpoints after they have been created(on config load).
Update1:
As per your comment the solution with option would be like the following.
Seperate the properties loading part of the config into another config.
Like "mapping-core-config.xml,mappingtest.xml" where the mapping-core-config will have the tags to load the properties file.
Now create a test config file for the mapping-core-config.xml file which loads the test properties file. This should be used in your test config. This way without modifying or disturbing your main code, you can test your flows pointing to temp folders.
"mapping-core-test-config.xml,mappingtest.xml"
Note: The test config can reside in the src/test/resources folders.
Hope this helps.

Liquibase execution order of changeset files when using includeAll with classpath*:

I am using liquibase (3.1.1) in a spring environment (3.2.x) and load the changesets via the inlcudeAll tag in a master file. There I use the "classpath*:/package/to/changesets" as path.
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<includeAll path="classpath*:/package/to/changesets"/>...
I use a naming strategy like "nnn_changesetname.xml" to keep ordering. But when I look into the changeset table this ordering via the filenames are not kept. Is this only working, if the changeset files are contained in a directory and not on the classpath?
Update
Hi, I found out that the below suggested solution is not enough. I think it lies in the implementation how liquibase resolves the includAll attribute. In my case it first resolves all "folders" and then looks into each folder for changeset xmls. This will break the ordering of the xml files in all classpath*:/changes locations, because there are now several "changes" folders in different locations. What I would suspect in such a case is a merge of all contents of this "virtual" classpath folders and loading of all resources in one enumeration. Or we could allow some resouce pattern in the inlcudeAll tag like resources="classpath*:/changes/*.xml" to directly select all needed files (tried it out with the path attribute, but did not work, because it checks for a folder)?
Update
I made a hack to check if the ordering in the returned enumeration is preserved with the anwser from below. To achive this I checked for the given package name and if it matches my pattern I added an additional "*.xml" to it. With this extension I get all changeset as needed.
#Override
public Enumeration<URL> getResources(String packageName)
throws IOException {
if(packageName.equals("classpath*:/plugin/liquibase/changes/")) {
packageName = packageName + "*.xml";
}
List<URL> resources = Collections.list(super.getResources(packageName));
Collections.sort(resources, new Comparator<URL>() {
#Override
public int compare(URL url1, URL url2) {
String path1 = FilenameUtils.getName(url1.getPath());
String path2 = FilenameUtils.getName(url2.getPath());
return String.CASE_INSENSITIVE_ORDER.compare(path1, path2);
}
});
logger.info("Found resources: {}", resources);
return Collections.enumeration(resources);
}};
In the log I can see now that the resources have the correct order. But when I look into the table DATABASECHANGELOCK it does not reflect the order I had in the enumeration. So it seems that this values get reodered somewhere else.
Update
Analyzed the code furhter and found out that the class liquibase.parser.core.xml.XMLChangeLogSAXHandler makes a reordering of the returned enumeration. So my changes will have no effect. I do not think that I can hack into this class as well.
You are right, Liquibase is relying on the underlying "list files" logic which orders files alphabetically through the file system but apparently does not through classpaths.
I created https://liquibase.jira.com/browse/CORE-1843 to track the fix.
For now, if you configure spring with a subclass of liquibase.integration.spring.SpringLiquibase that overrides getResources(String packageName) with a method that sorts the returned Enumeration that should resolve the problem for you.
So after some thinking and one night of sleep I came up with the following hack to guarantee order of the loaded changelog files via classpath pattern classpath*:/my/path/to/changelog/*.xml . The idea is to create the main changelog file on the fly via dom manipulation, when liquibase requests it.
It only works for the main changelog file. Following prerequisite:
The pattern can only be used for the main changelog file
I use an empty master changelog file as template
All other changelog files have to use the normal allowed loading mechanism
Works only in an Spring environment
First I had to extend/overwrite the liquibase.integration.spring.SpringLiquibase with my implementation.
public class MySpringLiquibase extends SpringLiquibase {
private static final Logger logger = LoggerFactory.getLogger(MySpringLiquibase.class);
private ApplicationContext context;
private String changeLogLocationPattern;
private List<String> changeLogLocations;
#Autowired
public void setContext(ApplicationContext context) {
this.context = context;
}
/**
* Location pattern to search for changelog files.
*
* #param changeLogLocationPattern
*/
public void setChangeLogLocationPattern(String changeLogLocationPattern) {
this.changeLogLocationPattern = changeLogLocationPattern;
}
#Override
public void afterPropertiesSet() throws LiquibaseException {
try {
changeLogLocations = new ArrayList<String>();
// retrieve all changelog resources for the pattern
List<Resource> changeLogResources = Arrays.asList(context.getResources(changeLogLocationPattern));
for (Resource changeLogResource : changeLogResources) {
// get only the classpath path of the resource
String changeLogLocation = changeLogResource.getURL().getPath();
changeLogLocation = "classpath:" + StringUtils.substringAfterLast(changeLogLocation, "!");
changeLogLocations.add(changeLogLocation);
}
// sort all found resources by string
Collections.sort(changeLogLocations, String.CASE_INSENSITIVE_ORDER);
} catch (IOException e) {
throw new LiquibaseException("Could not resolve changeLogLocationPattern", e);
}
super.afterPropertiesSet();
}
#Override
protected SpringResourceOpener createResourceOpener() {
final String mainChangeLog = getChangeLog();
return new SpringResourceOpener(getChangeLog()) {
#Override
public InputStream getResourceAsStream(String file)
throws IOException {
// check if main changelog file
if(mainChangeLog.equals(file)) {
// load master template and convert to dom object
Resource masterResource = getResourceLoader().getResource(file);
Document masterDocument = DomUtils.parse(masterResource, true);
// add all changelog locations as include elements
for (String changeLogLocation : changeLogLocations) {
Element inlcudeElement = masterDocument.createElement("include");
inlcudeElement.setAttribute("file", changeLogLocation);
masterDocument.getDocumentElement().appendChild(inlcudeElement);
}
if(logger.isDebugEnabled()) {
logger.debug("Master changeset: {}", DomUtils.toString(masterDocument));
}
// convert dom back to string and give it back as input resource
return new ByteArrayInputStream(DomUtils.toBytes(masterDocument));
} else {
return super.getResourceAsStream(file);
}
}
};
}
}
This class now needs to be used in the spring xml configuration.
<bean id="liquibase" class="liquibase.integration.spring.MySpringLiquibase"
p:changeLog="classpath:/plugin/liquibase/master.xml"
p:dataSource-ref="dataSource"
p:contexts="${liquibase.contexts:prod}"
p:ignoreClasspathPrefix="true"
p:changeLogLocationPattern="classpath*:/plugin/liquibase/changes/*.xml"/>
With this changes I have achieved that my main changelog files are ordered by their name.
Hope that helps others too.

How to switch from ResourceBundle to Properties (class)?

How to switch from ResourceBundle to Properties (class)?
I have an app split into 2 Java projects (core & web). A Java service in the core module have to read values from a .properties file located in the web module.
When I use ResourceBundle, it works as expected.
I wanted to switch to the Properties class for several reasons (esp. because the ResourceBundle is cached and I don't want to implement the ResourceBundle.Control to have no cache).
Unfortunately I can't get it to work, particularly because I can't find out which correct relative path to use.
I read the decompiled ResourceBundle class (et al.) and noticed the use of getResource() on some ClassLoader.
So instead of directly using FileInputStream, I tested with getResource() or simply getResourceAsStream() on ServiceImpl.class or ResourceBundle.class but still no success...
Anyone having an idea how to get this work? Thanks!
This is my app core with the service getting the property values:
app-core
src/main/java
com.my.company.impl.ServiceImpl
public void someRun() {
String myProperty = null;
myProperty = getPropertyRB("foo.bar.key"); // I get what I want
myProperty = getPropertyP("foo.bar.key"); // not here...
}
private String getPropertyRB(String key) {
ResourceBundle bundle = ResourceBundle.getBundle("properties/app-info");
String property = null;
try {
property = bundle.getString(key);
} catch (MissingResourceException mre) {
// ...
}
return property;
}
private String getPropertyP(String key) {
Properties properties = new Properties();
InputStream inputStream = new FileInputStream("properties/app-info.properties"); // Seems like the path isn't the good one
properties.load(inputStream);
// ... didn't include all the try/catch stuff
return properties.getProperty(key);
}
This is the web module where resides the properties file:
app-web
src/main/resources
/properties
app-info.properties
You should use getResource() or getResourceAsStream() with proper path and classloader.
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("properties/app-info.properties");
Make sure the file is named app-info.properties, and not something like app-info_en.properties which would be found by ResourceBundle (when the context matches) but not by getResourceAsStream().
You should not be trying to read the properties from the filesystem. Change your method that gets properties to load them from a resource stream instead. Pseudo code:
private String getPropertyP(final String key) {
final Properties properties = new Properties();
final InputStream inputStream = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("properties/app-info.properties");
properties.load(inputStream);
return properties.getProperty(key);
}

Categories

Resources