I have tried a ton of variants of the below to get datasources to work but to no avail. I have been researching/trying for a few days now so I'm throwing in the towel and asking for help. First off though, I am having a hard time formating my code in this post. Nothing is getting indented and certain xml tags are disappearing. Probably stupid IE that work forces us to use....
web.xml
<resource-ref>
<res-ref-name>jdbc/nalabor</res-ref-name>
<res-type>oracle.jdbc.pool.OracleDataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
<res-ref-name>jdbc/navarch</res-ref-name>
<res-type>oracle.jdbc.pool.OracleDataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource
name="jdbc/nalabor" type="oracle.jdbc.pool.OracleDataSource"
maxActive="1" maxIdle="1" maxWait="10000"
factory="oracle.jdbc.pool.OracleDataSourceFactory"
url="jdbc:oracle:thin:#####.com:1521:SID"
driverClassName="oracle.jdbc.driver.OracleDriver"
username="###" password="###"/>
<Resource
name="jdbc/navarch" type="oracle.jdbc.pool.OracleDataSource"
maxActive="1" maxIdle="1" maxWait="10000"
factory="oracle.jdbc.pool.OracleDataSourceFactory"
url="jdbc:oracle:thin:#####.com:1521:SID"
driverClassName="oracle.jdbc.driver.OracleDriver"
username="###" password="###"/>
</Context>
Dao
try {
Context initContext = new InitialContext();
NamingEnumeration list = initContext.list("java:/comp/env");
System.out.println("Listing NamingEnumeration For java:/comp/env");
while (list.hasMore()) {
NameClassPair nc = (NameClassPair)list.next();
System.out.println("Name Class Pair = " + nc);
}
list = initContext.list("java:/comp/env/jdbc");
System.out.println("Listing NamingEnumeration java:/comp/env/jdbc");
while (list .hasMore()) {
NameClassPair nc = (NameClassPair)list .next();
System.out.println("Name Class Pair = " + nc);
}
Context envContext = (Context) initContext.lookup("java:/comp/env");
ods = (OracleDataSource) envContext.lookup("jdbc/nalabor");
} catch (Exception ex) {
System.out.println("ERORRRRRRRR AGAIN!");
ex.printStackTrace();
}
Stack
Listing NamingEnumeration For java:/comp/env
Name Class Pair = mailClient: java.lang.String
Name Class Pair = siteConnCache: java.lang.String
Name Class Pair = jdbc: org.apache.naming.NamingContext
Name Class Pair = sitePOCEmail: java.lang.String
Name Class Pair = siteFilePrefix: java.lang.String
Name Class Pair = siteName: java.lang.String
Name Class Pair = siteEmail: java.lang.String
Listing NamingEnumeration java:/comp/env/jdbc
Name Class Pair = nalabor: org.apache.naming.ResourceRef
Name Class Pair = navarch: org.apache.naming.ResourceRef
ERORRRRRRRR AGAIN!
javax.naming.NamingException: Cannot create resource instance
at org.apache.naming.factory.ResourceFactory.getObjectInstance(ResourceFactory.java:167)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:314)
at org.apache.naming.NamingContext.lookup(NamingContext.java:834)
at org.apache.naming.NamingContext.lookup(NamingContext.java:181)
at org.apache.naming.NamingContext.lookup(NamingContext.java:822)
at org.apache.naming.NamingContext.lookup(NamingContext.java:194)
at com.gdebI.rozycki.bsc.data.LaborDAO.getWeightedLabor(LaborDAO.java:91)
at com.gdebI.rozycki.bsc.controller.action.WeightedLabor.getList(WeightedLabor.java:66)
at com.gdebI.rozycki.controller.action.ListAction.service(ListAction.java:38)
WEB-INF/lib
ojdbc14.jar
I'm not sure why you listed your resources in your web.xml but I think you are including an extra / that is causing the problem. I've encountered this exception when the name can't be found. Try this (Java 6+):
OracleDataSource ods = InitialContext.doLookup("java:comp/env/jdbc/nalabor");
or this for Java 5 and below:
InitialContext ic = new InitialContext();
OracleDataSource ods = (OracleDataSource)ic.lookup("java:comp/env/jdbc/nalabor");
I meet this problem and I solve it . notice your the order of elements in your web.xml. I resort the order of element in My web app's web.xml as the http://wiki.apache.org/tomcat/Specifications says and it works.
Related
I have a requirement to read information that is available in the META/MANIFEST.MF file of Spring Boot MVC web application and use this info to perform some business logic. I'm using gradle to build the application as war file and deploying it into the external tomcat.
I have tried the following:
#Configuration
public class AppConfig
{
#Bean("manifest")
public java.util.jar.Manifest getManifest() throws IOException
{
InputStream inputFile = this.getClass().getClassLoader().getResourceAsStream("META-INF/MANIFEST.MF");
Manifest manifestObj = new Manifest(inputFile);
return manifestObj;
}
}
AppService.java
#Service
public class AppService
{
#Autowired
#Qualifier("manifest")
private Manifest manifest;
#PostConstruct
public String init()
{
Attributes mainAttributes = manifest.getMainAttributes();
String buildNum = mainAttributes.getValue("Build-Number");
String customPropInfo= mainAttributes.getValue("customPropInfo");
String systemPrp1= buildNum + "_" + "SomeBusinessInfoLogic1";
String systemPrp2= customPropInfo+ "_" + "SomeBusinessInfoLogic2";
//Some Business Logic with these attributes systemPrp, systemPrp2
logger.info("System Props are updated");
}
}
I'm getting null for both buildNum and customPropInfo.
Note: I have tried creating the Manifest bean something like this which was created by me. As per the #M.Deinum suggestion I'm creating this new question here. I also tried the solutions here which didn't work for me.
#M.Deinum suggested to make use of Spring Boot's Actuator Info endpoint. But this endpoint is useful when we want to access the info outside of the application but my requirement is different as I need the data that is available in MANIFEST.MF file to perform some business operations within the application.
I get the following error when I tried this solution "/META-INF/MANIFEST.MF".
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'manifest' defined in class path resource [com/abc/AppConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.jar.Manifest]: Factory method 'getManifest' threw exception; nested exception is java.lang.NullPointerException: Cannot invoke "java.io.InputStream.read(byte[], int, int)" because "this.in" is null
Can someone please help me to read information from META/MANIFEST.MF of the Spring Boot MVC Web Application?.
UPDATE1: I get the following MainAttributes when I try to print MainAttributes. But the problem is when I try to deploy the war into external tomcat.
System.out.println("Manifest MainAttributes = " +manifestObj.getMainAttributes().keySet());
Output:
Manifest MainAttributes = [Manifest-Version, Implementation-Title, Automatic-Module-Name, Implementation-Version, Built-By, Spring-Boot-Jar-Type, Build-Jdk-Spec]
UPDATE2:
I have updated to AppService.java to print the info available in autowired Manifest object. Something like below:
#Configuration
public class AppConfig
{
#Bean("manifest")
public java.util.jar.Manifest getManifest() throws IOException
{
InputStream inputFile = new ClassPathResource("/META-INF/MANIFEST.MF").getInputStream();
Manifest manifestObj = new Manifest(inputFile);
System.out.println("Manifest Manifest-Version = " +manifestObj.getMainAttributes().getValue("Manifest-Version"));
System.out.println("Manifest KeySet = " +manifestObj.getMainAttributes().keySet());
return manifestObj;
}
}
#Service
public class AppService
{
#Autowired
#Qualifier("manifest")
private Manifest manifest;
#PostConstruct
public String init()
{
Attributes mainAttributes = manifest.getMainAttributes();
mainAttributes.forEach((k,v) -> {
System.out.println("AppService.init(): Key = "+k+", Value = "+v);
});
String buildNum = mainAttributes.getValue("Build-Number");
String customPropInfo= mainAttributes.getValue("customPropInfo");
String systemPrp1= buildNum + "_" + "SomeBusinessInfoLogic1";
String systemPrp2= customPropInfo+ "_" + "SomeBusinessInfoLogic2";
//Some Business Logic with these attributes systemPrp, systemPrp2
logger.info("System Props are updated");
}
}
I see the following output on the console:
AppService.init(): Key = Implementation-Title, Value = Apache Tomcat Bootstrap
AppService.init(): Key = Implementation-Version, Value = 9.0.12
AppService.init(): Key = Specification-Vendor, Value = Apache Software Foundation
AppService.init(): Key = Specification-Title, Value = Apache Tomcat Bootstrap
AppService.init(): Key = Class-Path, Value = commons-daemon.jar
AppService.init(): Key = Manifest-Version, Value = 1.0
AppService.init(): Key = Main-Class, Value = org.apache.catalina.startup.Bootstrap
AppService.init(): Key = Implementation-Vendor, Value = Apache Software Foundation
AppService.init(): Key = Ant-Version, Value = Apache Ant 1.9.9
AppService.init(): Key = X-Compile-Target-JDK, Value = 1.8
AppService.init(): Key = X-Compile-Source-JDK, Value = 1.8
AppService.init(): Key = Created-By, Value = some xyz
AppService.init(): Key = Specification-Version, Value = 9.0
So just by the above output, I think MANIFEST.MF is not application specific but is from commons-daemon.jar.
OK - the problem isn't that you "can't read data from META/MANIFEST.MF in Spring Boot MVC Web Application". Rather, the problem is that your code happens to be reading the WRONG MANIFEST.MF from some other, random .jar in the classpath.
One solution might be to use JarClassLoader.
Another solution, as M. Deinum suggested, might be to store the properties you wish to retrieve in application.properties (or some other "global" properties file) instead of MANIFEST.MF.
ALSO:
I assume you're probably using an IDE to develop your app (Eclipse, Netbeans, etc). If you haven't already, I would STRONGLY encourage you to familiarize yourself with your IDE's debugger: the ability to set breakpoints, display variables, single-step through method calls, etc.
I am in the process of migrating existing VMSS tomcat project to AKS. In VM, we use server.xml to provide environment variables using <Environment .../> tags. For Kubernetes, I am using env: field to replace these values.
In the project, there is code Config.java:
private Object getObject(String key) {
try {
log.debug("looking up key: " + key + " in environment context.");
Object rtn = getEnvContext().lookup(key);
log.debug("Found property for " + key + ": " + rtn);
return rtn;
} catch (NamingException e) {
log.debug("Unable to find key: " + key);
return null;
}
}
private Context getEnvContext() throws NamingException {
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
return envCtx;
}
From what is java:comp/env?, it says that java:comp/env is the node in the JNDI tree where you can find properties for the current Java EE component.
Here are my questions.
When tomcat starts, does it use server.xml <Environment .../> tag to create properties in the node in the JNDI tree? (thus, when .getObject(someString) is called, it can get the value defined in server.xml)
If I want to replace server.xml with Helm chart env field, will these properties (defined in Helm) be defined in the node in the JNDI tree? or do I need to define these beans in jndi.xml as JndiObjectFactoryBean?
I am sorry if I am not making sense at all here. I am very new to tomcat and concept of JNDI and JNDI tree. Please let me know if I need to clarify myself.
I wanted to retrieve values from my context.xml, and I've found this snippet of code to do so:
// Acquire an instance of our specified bean class
MyBean bean = new MyBean();
// Customize the bean properties from our attributes
Reference ref = (Reference) obj;
Enumeration addrs = ref.getAll();
while (addrs.hasMoreElements()) {
RefAddr addr = (RefAddr) addrs.nextElement();
String name = addr.getType();
String value = (String) addr.getContent();
if (name.equals("foo")) {
bean.setFoo(value);
} else if (name.equals("bar")) {
try {
bean.setBar(Integer.parseInt(value));
} catch (NumberFormatException e) {
throw new NamingException("Invalid 'bar' value " + value);
}
}
}
// Return the customized instance
return (bean);
I wanted to know if there was a method to do the exact same thing but with less steps
a web application on Tomcat 8.0
Tomcat 8.0 has reached End of Life. Do not use it. See "Migration Guide" at tomcat.apache.org to upgrade to Tomcat 8.5 or 9.0.
See "JDNI Resources" in Tomcat documentation. E.g. factory="org.apache.naming.factory.BeanFactory" can be used to create an arbitrary bean.
If you just need a set of configurable properties, defining them with "Parameter" element in Context will be easier. A web application will get those values via javax.servlet.ServletContext.getInitParameter(name) API.
When I try to get a sessionconfig by the index that exist in the file that contains the sessionConfig (in our case "InitiatorSettings.cfg")
[default]
FileStorePath=data
FileLogPath=log
HeartBtInt=30
ReconnectInterval=5
[session]
SessionName=badisInit1
BeginString=FIX.4.2
SenderCompID=client1
TargetCompID=server1
ConnectionType=initiator
SocketConnectPort=9878
SocketConnectHost=localhost
UseDataDictionary=N
[session]
SessionName=init0badis
BeginString=FIX.4.2
SenderCompID=client1
TargetCompID=server12
ConnectionType=initiator
SocketConnectPort=9878
SocketConnectHost=localhost
UseDataDictionary=N
[session]
SessionName=test211
BeginString=FIX.4.2
SenderCompID=badis
TargetCompID=server
ConnectionType=initiator
SocketConnectPort=9878
SocketConnectHost=localhost
UseDataDictionary=N
I get sessions in different orders, in just the first two sessionIDs:
get session id FIX.4.2:client1->server12
get session id FIX.4.2:client1->server1
get session id FIX.4.2:badis->server
there is the code that I have used to load the sessions and print them
I don't know if it is normal to have different orders in the file and after we load them, or there is something wrong with my config file ..
SessionSettings sessionSettings = new SessionSettings("InitiatorSettings.cfg");
ApplicationImp mainApplication = new ApplicationImp();
FileStoreFactory fileStoreFactory = new FileStoreFactory(sessionSettings);
FileLogFactory logFactory = new FileLogFactory(sessionSettings);
MessageFactory messageFactory = new DefaultMessageFactory();
socketInitiator = new SocketInitiator( mainApplication,
fileStoreFactory, this.sessionSettings, logFactory,
messageFactory);
for(int i=0;i<socketInitiator.getSessions().size();i++)
{
System.out.println("get session id "+socketInitiator.getSessions().get(i));
}
Thanks for the help.
It is normal behavior that the sessions are not ordered as the SessionID->Sessions are stored in a HashMap and converted to a List on the getSessions() method.
from SessionConnector (superclass of SocketInitiator)
public ArrayList<SessionID> getSessions() {
return new ArrayList<SessionID>(sessions.keySet());
}
(As a reminder, a HashMap doesn't guarantee order of the put() call. You would need LinkedHashMap for that.)
A suggestion aside from modifying the core code, would be to add a property will an ordered list of the sessionIDs and iterate through that property and look it up in the getSessionMap()
I am migrating an app from WAS4 to WAS6.1
A piece of code is as follows:
javax.naming.Context ctx = new javax.naming.InitialContext();
javax.sql.DataSource ds = (javax.sql.DataSource)ctx.lookup(JNDI_NAME);
dsvalue_data = new Hashtable();
confvalue_data = new Hashtable();
// Parse the datasource string and get the properties
// writeInfo will return the name of the datasource and will populate the
// dsvalue_data and confvalue_data hashtables with datasource and
// connection pool properties
String tableHeader = writeInfo(ds.toString());
aResultHandler.addObject(CV_ABOUT_DESC,tableHeader);
aResultHandler.addObject(CV_ABOUT_PAGE,dsvalue_data);
.....
.....
The problem is in WAS6.1, this ds.toString() does not give the human readable properties of the datasource
It just gives the object name (like com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource#a21fg7) when i tried to print.
what should I do to get and print all the properties of the datasource?
After obtaining your datasource ds, you can get database information like this:
DatabaseMetaData md = ds.getConnection().getMetaData();
There are tons of methods to be used, you can get a list from official documentation.
#Pangea
In Was4,ds.toString() gives the details of the datasource in a readable format
which is then formatted to display the properties..like
errorMap = null
logOrphan = false
connTimeout = 180
TransactionBranchesLooselyCoupled = false
resetReadOnly = false
maxConnectionPoolSize = 10
autoConnectionCleanupDisabled = false
minConnectionPoolSize = 1
secureXACredential = false
surgeThreshold = -1
informixLockModeWait = 0
dataBaseVersion = 0
validationSQL = null
oracleStmtCacheSize = 0
orphanTimeout = 1800
stuckThreshold = -1
surgeTime = 20
stuckTime = 30
diagOptions = 0
connectionValidation = false
maxStatementCacheSize = 10
stuckTimerTime = 5
idleTimeout = 1800
What is your main objective? DataSource as such doesn't expose the properties your are looking for. May be you are confused by the aResultHandler API.
I will start with saying that you need to get rid of the aResultHandler API or refactor it to make use of DataSource.
If you doesn't have that option for whatever insane reason below is another option. Not sure if this works.
Depending upon the toString() was a bad choice made and hence your in this trouble. I suggest you try to cast the DataSource returned from JNDI lookup to WAS implementation class (do ds.getClass() to see what is the actual impl class) and see if these properties are exposed in some way.