I am using JBoss 5.1 with Hibernate 3.6, JPA 2.0 and Spring 3.0.5.
I use maven to build the EAR file which looks like :
AutoTrader.ear
-------> META-INF
--------------> application.xml
--------------> jboss-app.xml
--------------> MANIFEST.MF
-------> AutoTrader.war
if I deploy this ear file in JBoss 5.1, i get the error
org.springframework.dao.InvalidDataAccessApiUsageException: Not an entity: class uk.co.aol.shipmanager.domain.Manager; nested exception is ja
va.lang.IllegalArgumentException: Not an entity: class uk.co.aol.shipmanager.domain.Subscription
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:286) ~[at_war-1.0.war:3
.0.5.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:104) ~[at_war-1.0.war:3.0.5.RELEASE
]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:368) ~[at_war-1.
0.war:3.0.5.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58
) ~[at_war-1.0.war:3.0.5.RELEASE]
However, if I deploy the war file exploded, it works fine.
Any suggestions are welcome.
Thanks,
Adi
UPDATE:
I have added a ResourceScanner which extends NativeScanner:
public class ResourceScanner extends NativeScanner {
#Override
public Set<Class<?>> getClassesInJar(final URL jarToScan,
final Set<Class<? extends Annotation>> annotationsToLookFor) {
return super.getClassesInJar(patchUrl(jarToScan), annotationsToLookFor);
}
#Override
public Set<NamedInputStream> getFilesInJar(final URL jarToScan, final Set<String> filePatterns) {
return super.getFilesInJar(patchUrl(jarToScan), filePatterns);
}
#Override
public Set<Package> getPackagesInJar(final URL jarToScan,
final Set<Class<? extends Annotation>> annotationsToLookFor) {
return super.getPackagesInJar(patchUrl(jarToScan), annotationsToLookFor);
}
#Override
public String getUnqualifiedJarName(final URL jarToScan) {
return super.getUnqualifiedJarName(patchUrl(jarToScan));
}
/**
* Patch the VFS URL to a FILE protocol URL.
*
* #param url
* original URL.
* #return either the original, either the corresponding FILE protocol of given VFS URL.
*/
protected URL patchUrl(final URL url) {
String protocol = url.getProtocol();
if (protocol.equals("vfs")) {
try {
File file = new File(url.getFile());
return file.toURI().toURL();
} catch (final MalformedURLException e) {
return url;
} catch (IOException e) {
e.printStackTrace();
return url;
}
}
return url;
}
}
and, in spring-persistence.xml,
<property name="hibernate.ejb.resource_scanner" value="uk.co.aol.shipmanager.ResourceScanner"/>
This again works in the exploded war file.
But in case of a EAR file, the protocol is vfszip not vfs.
Please tell what to do???
did you tried to to use the following system parameter and see if it helped resolved the issue?
-Dorg.jboss.net.protocol.file.useURI=false
Related
I'm using a Spring Boot application. For now, the use of the plugins is very simple. I'm just following the tutorial. My plugin is started, I'm trying to find the extensions like this:
final List<MyExtensionPoint> sections = pluginManager.getExtensions(MyExtensionPoint.class);
but Pf4j doesn't return the extensions.
When I'm following the code execution, I can see this code in the AbstractExtensionFinder:
if (type.isAssignableFrom(extensionClass)) {
ExtensionWrapper extensionWrapper = createExtensionWrapper(extensionClass);
result.add(extensionWrapper);
log.debug("Added extension '{}' with ordinal {}", className, extensionWrapper.getOrdinal());
} else {
log.trace("'{}' is not an extension for extension point '{}'", className, type.getName());
if (RuntimeMode.DEVELOPMENT.equals(pluginManager.getRuntimeMode())) {
checkDifferentClassLoaders(type, extensionClass);
}
}
I can understand the program is not entering inside the condition because I have 2 different classloaders: PluginClassLoader (for the extension) and RestartClassLoader (from Spring for the interface of the extension point).
I don't understand why it will be a problem because I think to instanciate the extension class, the PluginClassloader will use the parent class loader (RestartClassLoader) to find the interface.
Where is my mistake ? How to fix it ?
Thank you.
I extended the DevelopmentPluginLoader to pass the Spring classloader.
public class MyDevelopmentPluginLoader extends DevelopmentPluginLoader {
private ClassLoader parentClassLoader;
/**
* #param pluginManager
*/
public MyDevelopmentPluginLoader(final PluginManager pluginManager, final ClassLoader parentClassLoader) {
super(pluginManager);
this.parentClassLoader = parentClassLoader;
}
#Override
protected PluginClassLoader createPluginClassLoader(final Path pluginPath, final PluginDescriptor pluginDescriptor) {
return new PluginClassLoader(pluginManager, pluginDescriptor, parentClassLoader);
}
}
and in my custom PluginManager, I created and instance of my PluginLoader:
protected PluginLoader createPluginLoader() {
final CompoundPluginLoader compoundPluginLoader = new CompoundPluginLoader();
final PluginLoader developmentPluginLoader = new MyDevelopmentPluginLoader(this, getClass().getClassLoader());
final PluginLoader jarPluginLoader = new JarPluginLoader(this);
final PluginLoader defaultPluginLoader = new DefaultPluginLoader(this);
// #formatter:off
return compoundPluginLoader.
add(developmentPluginLoader, this::isDevelopment).
add(jarPluginLoader, this::isNotDevelopment).
add(defaultPluginLoader, this::isNotDevelopment);
// #formatter:on
}
I would like to generate a blog posts overview. For that I want to read the html files from a folder inside the templates folder in the resources folder where Spring Boot stores its templates.
I tried that but it doesnt return an error but also list no files.
What is the way to go here?
Thanks
#Controller
public class Route {
#Autowired
private ResourceLoader resourceLoader;
#RequestMapping("/")
public String home() throws IOException {
final String path = "templates/blog";
final Resource res = resourceLoader.getResource("templates/blog");
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(res.getInputStream()))) {
reader.lines().forEachOrdered(System.out::println);
}
return "blog/a";
}
}
#Controller
public class Route {
#Value("classpath:templates/blog/*")
private Resource[] resources;
#RequestMapping("/")
public String home() throws IOException {
for (final Resource res : resources) {
System.out.println(res.getFilename());
}
return "blog/a";
}
}
did the trick to me.
You should be able to achieve this using NIO2.
In order for NIO2 to work, it requires the concept of FileSystem, and one can be created from the jar URI. Then this file system can be used with Files/Paths.
The code below contains two branches - the first handles loading the files from inside Jar, the second branch - when the code runs from IDE or via "mvn spring-boot:run".
All streams are being used via try-with-resources so they will be auto-closed.
The find function starts from the top of the file system and recursively searches for html files.
public static void readFile(String location) throws URISyntaxException {
URI uri = Objects.requireNonNull(ReadFromJar.class.getClassLoader().getResource(location)).toURI();
if (uri.getScheme().equals("jar")) { //inside jar
try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) { //build a new FS that represents the jar's contents
Files.find(fs.getPath("/"), 10, (path, fileAttr) -> // control the search depth (e.g. 10)
fileAttr.isRegularFile() //match only files
&& path.toString().contains("blog") //match only files in paths containing "blog"
&& path.getFileName().toString().matches(".*\\.html")) // match only html files
.forEach(ReadFromJar::printFileContent);
} catch (IOException ex) {
ex.printStackTrace();
}
}
else { //from IDE or spring-boot:run
final Path path = Paths.get(uri);
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(path)) {
dirStream.forEach(ReadFromJar::printFileContent);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void printFileContent(final Path file) {
try {
System.out.println("Full path: " + file.toAbsolutePath().toString());
Files.lines(file).forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
I am using SpringBoot for creating Services. Now for Exception Handling (Using #COntrollerAdvice), I am trying to create a library instead of creating same files in each Service. This is my Exception Handler
#ControllerAdvice
public class CustomExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(CustomExceptionHandler.class);
/*
* This handles constraint voilation exception.
* #param exception
*/
#ExceptionHandler(ConstraintViolationException.class)
#ResponseBody
public ResponseEntity<?> handleConstraintVoilationException(ConstraintViolationException exception){
logger.info("Inside SumsExceptionHandler.handleConstraintVoilationException()");
ValidationErrorResponse validationResponse = null;
for(ConstraintViolation<?> constraintViolation : exception.getConstraintViolations()) {
validationResponse = this.makeValidationResponse(constraintViolation);
}
return new ResponseEntity<>(validationResponse, HttpStatus.BAD_REQUEST);
}
/*
* This handles MethodArgument Type Mismatch Exception.
* #param ex
*/
#ExceptionHandler(MethodArgumentTypeMismatchException.class)
#ResponseBody
public ResponseEntity<?> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException exception){
logger.info("Inside SumsExceptionHandler.handleMethodArgumentTypeMismatchException()");
ValidationErrorResponse validationResponse = new ValidationErrorResponse();
validationResponse.setField(exception.getName());
validationResponse.setCode(exception.getRequiredType().getSimpleName());
validationResponse.setMessage(exception.getValue()+" must have valid input of type "+exception.getRequiredType().getSimpleName());
return new ResponseEntity<>(validationResponse, HttpStatus.BAD_REQUEST);
}
/*
* This handles Missing Servlet Request Parameter Exception.
* #param ex
*/
#ExceptionHandler(MissingServletRequestParameterException.class)
#ResponseBody
public ResponseEntity<?> handleMissingServletRequestParameterException(MissingServletRequestParameterException exception){
logger.info("Inside SumsExceptionHandler.handleMissingServletRequestParameterException()");
ValidationErrorResponse validationResponse = new ValidationErrorResponse();
validationResponse.setField(exception.getParameterName());
validationResponse.setCode(exception.getParameterType());
validationResponse.setMessage(exception.getMessage());
return new ResponseEntity<>(validationResponse, HttpStatus.BAD_REQUEST);
}
private ValidationErrorResponse makeValidationResponse(ConstraintViolation<?> constraintViolation) {
String fieldStr = constraintViolation.getPropertyPath().toString();
String field = null;
if(fieldStr != null) {
String[] fieldArr = fieldStr.split("\\.");
field = fieldArr[fieldArr.length-1];
}
return new ValidationErrorResponse(field,
constraintViolation.getMessageTemplate(),
constraintViolation.getMessage());
}
}
a) How do I create it a stand-alone library?(This is also a springboot Project)
b) How to then use it in other Projects?
a) How do I create it a stand-alone library?(This is also a springboot Project)
Create separate project with minimum dependencies.
b) How to then use it in other Projects?
Build that project, Use that project as a library by adding jar in classpath
According to the documentation:
Spring Boot makes it easy to create stand-alone, production-grade
Spring based Applications that you can "just run".
You can also use maven to generate a new package with the required dependencies, then you can add the dependency in pom.xml. Gets a lookup on creating dependencies with Maven.
create a new Maven Java Project with version and artifact Id ...
will package it as a jar
add your needed dependencies related to all common facilities will
provide
add your facilities implementation >>>Ex #ControllerAdvice ...
in your main project will include it as a dependency
Following are the modules in my project,
1. EJB module (version 3): We prepare ejb jar of this module and deploy on Weblogic11g server. It deals with database operation. It has #local, #Remote interface and #stateless classes implementing #local,#Remote interfaces.
2. Web Application : This web application takes inputs (user uploads file) from users, validates file and inserts data into database. It uses RMI.
Problem: On production (weblogic 11g server ) sometimes we observe exception saying $Proxy99 cannot be cast to "Remote interface name" (for different different classes) e.g com.xyz.fileProcessSetting.FileProcessSttgFacadeRemote.
But after some time when we again upload file, it gets uploaded successfully without any error.
Now, I do not understand how come these remote objects becomes temporarily unavailable? Never faced this issue on development/UAT environment. Also no idea how to reproduce and fix it.
Please help. Thanks in advance.
#Remote
public interface FileProcessSttgFacadeRemote {
//methods
}
#Local
public interface FileProcessSttgFacadeLocal {
//methods
}
#Stateless
public class FileProcessSttgFacade implements FileProcessSttgFacadeLocal, FileProcessSttgFacadeRemote {
//methods
}
in weblogic-ejb-jar.xml
<weblogic-enterprise-bean>
<ejb-name>FileProcessSttgFacade</ejb-name>
<stateless-session-descriptor>
<business-interface-jndi-name-map>
<business-remote>com.xyz.fileProcessSetting.FileProcessSttgFacadeRemote</business-remote>
<jndi-name>FileProcessSttgFacade</jndi-name>
</business-interface-jndi-name-map>
</stateless-session-descriptor>
</weblogic-enterprise-bean>
In web application also in ejb module whenever we want to call methods we use following lookup method to get remote object:
public class someclass extends EjbLocator {
public void someMethod(){
FileProcessSttgFacadeRemote fpfr = (FileProcessSttgFacadeRemote) getService("FileProcessSttgFacade");
//other code
}
}
Following is the class used for JNDI lookup:
public class EjbLocator {
public Object getService(final String jndiName) throws Exception {
try {
obj = getDefaultContext().lookup(jndiName);
} catch (final Exception exp) {
exp.printStackTrace();
}
return obj;
}
protected Context getDefaultContext() {
try {
final Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
env.put(Context.SECURITY_PRINCIPAL,"weblogic");
env.put(Context.SECURITY_CREDENTIALS, "password");
env.put(Context.PROVIDER_URL, "t3://<ip>:<port>");
defaultContext = new InitialContext(env);
return defaultContext;
} catch (final NamingException nExp) {
nExp.printStackTrace();
}
return null;
}
}
I am working on an existing system that uses log4j, I want to update to log4j2.
There is a custom spring bean that loads the configuration from a file. I need to keep this approach. I cannot use the "log4j.configurationFile" system property.
We have a properties file where the path to the current log4j.xml is specified ( NFS share )
The spring bean has this code ...
public class Log4jConfigurationBean implements ResourceLoaderAware,
InitializingBean {
private ResourceLoader resourceLoader;
private boolean enabled;
private String location;
/**
* Default, no argument constructor.
*/
public Log4jConfigurationBean() {
enabled = true;
}
/**
* Sets whether or not this bean should load an external configuration
* defined by {#link #setLocation(Resource)}. If <code>false</code>, this
* bean does nothing.
*
* <p>
* Default value is <code>true</code>.
* </p>
*
* #param enabled
* <code>false</code> causes this bean to do nothing
*/
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
/**
* Sets the location of the external log4j configuration (xml or properties)
* to be loaded.
*
* #param location
* the location of the external configuration to be loaded.
* #throws IllegalStateException
* if there is a problem resolving the location resource
* #throws NullPointerException
* if <code>resource</code> is <code>null</code>
*/
public void setLocation(final String location) {
this.location = StringUtils.trimToNull(location);
}
#Override
public void setResourceLoader(final ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
/**
* #throws IllegalStateException
* if enabled and no location has be set, or if the external
* configuration is neither xml or properties.
*/
#Override
public void afterPropertiesSet() throws Exception {
URL configURL = null;
if (null != location) {
try {
final Resource resource = resourceLoader.getResource(location);
if (null != resource) {
configURL = resource.getURL();
}
} catch (IOException e) {
throw new IllegalArgumentException(
"Could not resolve configuration location due to error: ",
e);
}
}
if (enabled && null == configURL) {
throw new IllegalStateException(
"Log4j configuration enabled, but configuration location is not set.");
}
if (enabled) {
if (configURL.getFile().toLowerCase().endsWith(".xml")) {
DOMConfigurator.configure(configURL);
} else if (configURL.getFile().toLowerCase()
.endsWith(".properties")) {
PropertyConfigurator.configure(configURL);
} else {
throw new IllegalStateException(
"Configuration must be properties or xml: "
+ configURL.getFile());
}
}
}
}
In log4j2 there is no PropertyConfigurator.
How can I load the log4j2.xml file the same way.
The file path to the log4j2.xml file is specified in a spring property file.
The goal is to have the war files contain a log4j2.xml file in the classpath. This will be used when developing on your local box.
When the web apps are deployed to a qa environment, there is a property file containing the following key/value pair...
# Should an external file be used for log4j configuration
log4j.enabled=true
log4j.location=file:/paht to log4j2.xml
A spring bean is using these values to decide if an external log4j2.xml file should be used instead of the one on the classpath.
I tried with a spring bean like this... the code is executed, but it still uses the configuration file on the classpath.
public class Log4j2ConfigurationBean implements ResourceLoaderAware, InitializingBean {
private static final Logger log = LoggerFactory.getLogger(Log4j2ConfigurationBean.class);
private ResourceLoader resourceLoader;
private boolean enabled;
private String location;
/**
* Default, no argument constructor.
*/
public Log4j2ConfigurationBean() {
enabled = true;
}
/**
* Sets whether or not this bean should load an external configuration defined by {#link #setLocation(Resource)}. If <code>false</code>, this bean does nothing.
*
* <p>
* Default value is <code>true</code>.
* </p>
*
* #param enabled
* <code>false</code> causes this bean to do nothing
*/
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
/**
* Sets the location of the external log4j configuration (xml or properties) to be loaded.
*
* #param location
* the location of the external configuration to be loaded.
* #throws IllegalStateException
* if there is a problem resolving the location resource
* #throws NullPointerException
* if <code>resource</code> is <code>null</code>
*/
public void setLocation(final String location) {
this.location = StringUtils.trimToNull(location);
}
#Override
public void setResourceLoader(final ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
/**
* #throws IllegalStateException
* if enabled and no location has be set, or if the external configuration is neither xml or properties.
*/
#Override
public void afterPropertiesSet() throws Exception {
URL configURL = null;
if (enabled) {
if (StringUtils.isBlank(location)) {
throw new IllegalStateException("Log4j2 configuration enabled, but configuration location is not set.");
}
try {
System.out.println(this.getClass().getName() + " : Loading log4j2 configuration with " + location);
final Resource resource = resourceLoader.getResource(location);
if (null != resource) {
configURL = resource.getURL();
}
} catch (IOException e) {
throw new IllegalArgumentException("Could not resolve configuration location due to error: ", e);
}
if (configURL.getFile().toLowerCase().endsWith(".xml")) {
try {
System.setProperty("Log4jContextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");
System.setProperty("AsyncLogger.RingBufferSize", "8192");
ConfigurationFactory configurationFactory = XmlConfigurationFactory.getInstance();
ConfigurationSource configurationSource = new ConfigurationSource(configURL.openStream(), configURL);
Configuration configuration = configurationFactory.getConfiguration(configurationSource);
configuration.start();
log.info("Log4j2 configured with {}", location);
log.info("System property Log4jContextSelector set to {}", System.getProperty("Log4jContextSelector"));
log.info("System property AsyncLogger.RingBufferSize set to {}", System.getProperty("AsyncLogger.RingBufferSize"));
} catch (Exception e) {
System.out.println(this.getClass().getName() + " : Could not initialize log4j2 with resource " + location);
System.out.println(e.getStackTrace());
}
} else {
throw new IllegalStateException("Configuration must be xml: " + configURL.getFile());
}
} else {
System.out.println(this.getClass().getName() + " : External log4j2 configuration not configured.");
}
}
}
Thanks.
Check out the How do I configure log4j2 in code without a configuration file? section here - http://logging.apache.org/log4j/2.x/faq.html