I am trying to run a demo class (JMSJNDIProducer.java) that comes with Websphere MQ 7.0 installation at 'websphere installation location'\tools\jms\samples. I have Websphere up and running, below are my websphere configurations...
Queue Manager Name: JMSDEMO
Queue Manager Port: 1414
Channel (default): SYSTEM.DEF.CLNTCONN
Queue Name: JMSDEMO.QL
let me know if more info needed...
My code is failing during the initial context creation, I'm very new to Websphere MQ and not sure what the initialContextUrl needs to be?
public class JMS_JNDI_Websphere_Sample {
private static String initialContextUrl = "tcp://localhost:1414";
public static void main(String args[]) {
// Instantiate the initial context
String contextFactory = "com.sun.jndi.fscontext.RefFSContextFactory";
Hashtable<String, Object> environment = new Hashtable<String, Object>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
environment.put(Context.PROVIDER_URL, initialContextUrl);
try {
Context context = new InitialDirContext(environment);
} catch (NamingException e) {
e.printStackTrace();
}
System.out.println("Initial context found!");
}
}
I am getting the below exception.
javax.naming.InvalidNameException: tcp://localhost:1414 [Root exception is java.net.MalformedURLException: unknown protocol: tcp]
at com.sun.jndi.fscontext.FSContextFactory.getFileNameFromURLString(FSContextFactory.java:119)
at com.sun.jndi.fscontext.RefFSContextFactory.createContext(RefFSContextFactory.java:41)
at com.sun.jndi.fscontext.RefFSContextFactory.createContextAux(RefFSContextFactory.java:47)
at com.sun.jndi.fscontext.FSContextFactory.getInitialContext(FSContextFactory.java:49)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.InitialContext.<init>(InitialContext.java:197)
at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:82)
at com.hcsc.jms.websphere.jndi.JMS_JNDI_Websphere_Sample.main(JMS_JNDI_Websphere_Sample.java:32)
Caused by: java.net.MalformedURLException: unknown protocol: tcp
at java.net.URL.<init>(URL.java:574)
at java.net.URL.<init>(URL.java:464)
at java.net.URL.<init>(URL.java:413)
at com.sun.jndi.fscontext.FSContextFactory.getFileNameFromURLString(FSContextFactory.java:117)
... 9 more
private static String initialContextUrl = "tcp://localhost:1414";
First off, I don't think "tcp" is a valid value and if it is, do you have something running on port 1414 to reply JNDI lookup requests?
Secondly, I think you are confusing MQ port 1414 with JNDI lookup.
Third, why don't you just follow the example in JmsJndiProducer.java and use a file-based JNDI.
i.e. Use MQ Explorer and select "JMS Administered Objects" then do file-based JNDI.
Once you create your file-based JNDI then that value for your initial context.
You need to separate out the concept of messaing as provided by the JMS API, and the lookup of an object via JNDI. As Roger said the issue is confusion between the MQ listener and the JNDI URL
JNDI is split into the interface used to bind and lookup objects in the directory and the 'service providers' that take the object and put into some persistent store. The com.sun.jndi.fscontext.RefFSContextFactory is a service provider that uses the file system, so the URL for this needs to be an EXISTING directory. When objects are 'bound' into that the .bindings file is created (or updated if objects are already there). You don't need to create the .bindings file; that file is created for you by the File System Context. Also don't modify this by hand.
Typically you would use a LDAP backed JNDI service provider for production usage. The 'lookup' APIs used in the application are the same; what would change are the provider URL (as the location of the LDAP server would be provided) and possible the object name.
Would suggest reviewing Oracle's JNDI tutorial ..
Related
I am trying to deploy an ear file to a Weblogic 12 server. The ear file contains a HttpServlet. During deployment, the HttpServlet is trying to initialize and fails with this error:
Target state: deploy failed on Cluster
javax.naming.NameNotFoundException: While trying to lookup
'jdbc.' didn't find subcontext 'jdbc'. Resolved
'' at
weblogic.jndi.internal.BasicNamingNode.newNameNotFoundException(BasicNamingNode.java:1180)
I tested the data source connection on the weblogic servers and it is successful.
The data source is defined in a properties file that is being accessed because the datasource name is correct. The webserver URL is also correct.
This is the init() method:
public void init(ServletConfig config) throws ServletException
{
super.init(config);
Context jndiContext = null;
Hashtable ht = new Hashtable();
try
{
PropertyManager.getInstance(PROPS_FILE);
PropertyManager.getInstance();
ht.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, PropertyManager.getProperty("WL_WEBSERVER_URL"));
jndiContext = new InitialContext(ht);
ds = (javax.sql.DataSource) jndiContext.lookup(PropertyManager.getProperty("SEC_DATASOURCE"));
}
}
I don't understand why it does not recognize the subcontext of jdbc.
I tried removing jdbc. But the error is a NameNotFoundException without jdbc.
UPDATE
I tried changing the data source name to java:jdbc/scantDS. I received a different NameNotFoundException:
". javax.naming.NameNotFoundException: While
trying to look up /jdbc/scantDS in /app/webapp/Load/421643657.;
remaining name '/jdbc/scantDS' at
weblogic.jndi.internal.BasicNamingNode.newNameNotFoundException(BasicNamingNode.java:1180)
The problem was that I was trying to deploy using the wrong port number. I was using the port number that the console application was using and I needed a specific port that has the JNDI.
Trying to use WOLA direct from a webapp in Liberty to CICS. Using same CICS region successfully with z/OS Connect V2 (zCEE). With Liberty, I have configured:
<featureManager>
<feature>servlet-3.1</feature>
<feature>jndi-1.0</feature>
<feature>jaxrs-1.1</feature>
<feature>zosLocalAdapters-1.0</feature>
</featureManager>
and
<!-- WOLA group to which others register -->
<zosLocalAdapters wolaGroup="GROUP" wolaName2="LIBRTOLA" wolaName3="WOLA3" />
<connectionFactory id="wolaCF" jndiName="eis/ola">
<properties.ola RegisterName=CICSMLAW/>
</connectionFactory>
<resourceAdapter location="/usr/lpp/IBM/zosconnect/v2r0/wlp/lib/ola.rar"/>
In the messages.log, I see good and bad items there:
CWWKB0103I: Authorized service group WOLA is available The WebSphere Optimized Local Adapter channel registered with the Liberty profile server using the following name: GROUP LIBRTOLA WOLA3
and the bad:
com.ibm.ws.app.manager.AppMessageHelper E CWWKZ0013E: It is not possible to start two applications called ola.
So the failure on registration: Requestlgth: 97
Requestparms data 1: BBOC START_SRVR RGN=CICSMLA DGN=GROUP NDN=LIBRTOLA
Requestparms data 2: SVN=WOLA3 SVC= MNC=1 MXC=10 TXN=N SEC=N REU=N
Requestparms data 3:
Processing a START SERVER request.
Starting WAS adapters Server task ...
Server transaction id will be: BBO$
Link transaction defaults to: BBO#
Service name will be:
Trace TDQ: BBOQ
Processing a REGISTER API request.
Register name: CICSMLA string len: 7
WAS Daemon: GROUP WAS Node: LIBRTOLA WAS Server: WOLA3
Min. connections: 1
Max. connections: 10
Transactional: N string len: 1
Security propagation: N string len: 1
Invoking OLA Register API for CICSMLA .
on with the Liberty profile server was not successful. The return code is 8, and the reason code 8.
And the failure in the JNDI call:
Context ctx = new InitialContext();
ConnectionFactory cf = (com.ibm.ws390.ola.jca.ConnectionFactoryImpl)ctx.lookup("java:comp/env/eis/ola");
Results in error:
[err] javax.naming.NameNotFoundException: javax.naming.NameNotFoundException: java:comp/env/eis/ola
[err] at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext.lookup(JavaURLContext.java:356) [err] at [internal classes]
[err] at javax.naming.InitialContext.lookup(InitialContext.java:428)
[err] at com.ibm.ctl.bank.impls.CTLBankWolaImpl.(CTLBankWolaImpl.java:51)
[err] at com.ibm.ctl.bank.web.OLTPBankRest.setImpl(OLTPBankRest.java:235)
Thanks
You have a lot going on here.
I'm not sure why you're starting ola.rar from the z/OS Connect v2 product, inside of a Liberty server. The zosLocalAdapters-1.0 feature already loads the ola.rar that ships with Liberty. You should remove the configuration from server.xml. That should resolve the CWWKZ0013E error.
You should see two CWWKB0103I messages in messages.log, one for WOLA (which you included) and one for CLIENT.WOLA. Please be sure you see both. It's possible you're on a very old version of Liberty that doesn't print the second CWWKB0103I message, so if this is true, please disregard that part.
I don't think you would have gotten this far without finding the WOLA configuration instructions for the Liberty server in the knowledge center, but here they are for other's benefits:
https://www.ibm.com/support/knowledgecenter/en/was_beta_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_dat_enableconnector.html
OK next, I can't see your application to know whether you've got a resource-reference to a connection factory configured. I assume you do because you're doing a java:comp/env lookup. You do not need to cast to com.ibm.ws390.ola.jca.ConnectionFactoryImpl, and actually I highly recommend removing that since that is an internal class and subject to change at any time. It may be that the application class loader doesn't have access to that class, and that may be part of the problem.
Finally, you have a problem in CICS starting the link server. You are getting RC=8 RSN=8. A list of services and return/reason codes can be found here:
https://www.ibm.com/support/knowledgecenter/en/was_beta_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/rwlp_dat_olaapis.html
An 8/8 on BBOA1REG (register) indicates the register token is already in use. Basically, the RGN= name you picked is already in use. Are you sure there isn't a PLTPI transaction or something else in the CICS region that is already registered with that name? Perhaps try a different name just to see if it works, and if it does, maybe try BBOC LIST_SRVR to see what it is? It's difficult to say how it's getting started without knowing more about your system.
I hope this helps. Take care!
Is it possible to set environment variables at the application level in websphere?
Websphere servers can host multiple applications. Any environment variable applied at the server level applies to all the applications on that server. Is it possible to create variables that only apply to individual applications?
For example:
Lets say we have a SpreadsheetApp and a DocsApp running on the same server. They both share some common code that can be configured via an environment variable called DocStorageLocation. Is it possible to set the DocStorageLocation differently for both applications?
Alternatively, is there another way of configuring multiple applications running on the same server?
QUESTION 1
Is it possible to set the DocStorageLocation differently for both
applications?
I don't think it is possible. Websphere's environment variables are meant to be used by the server itself. A variable has only three possible scopes, which are Server, Cluster and Node.
For instance, an ORACLE_JDBC_DRIVER_PATH environment variable on server1, node1 scope could be used for the JDBC provider on node1 (classPath = ${ORACLE_JDBC_DRIVER_PATH}/ojdbc14.jar).
The question is : "why can't I set a different value for my application only" ? But my guess is that as long as the server, clusters and nodes are started, it does not make sense to override this value for a deployed application.
Although I think it is not possible, I still tried. But I did not manage to override an environment variable set for the websphere server.
QUESTION 2
Alternatively, is there another way of configuring multiple
applications running on the same server?
Environment entry
You could add an environment entry to your web.xml deployment descriptor, a variable you can look up for.
<env-entry>
<env-entry-name>DocStorageLocation</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>C:/DocStorage</env-entry-value>
</env-entry>
Then test, look up for this variable in the java class :
//TEST
Object l_test = null;
try {
Context l_ctx = new InitialContext();
l_test = l_ctx.lookup("java:comp/env/DocStorageLocation");
} catch (NamingException e1) {
// TODO
e1.printStackTrace();
}
URL ressource for .properties file
You can create an URL ressource. It would link to a .properties file set on a local host or any server, so each property could be set to a different value depending on the environment.
For instance, JNDI name url/environmentJndiName with value file:///server1/environment.properties on server1, and file:///server2/environment.properties on server2.
Then on server 1, you could set docStorageLocation=value1 in the environment.properties file, docStorageLocation=value2 on server2.
In your deployment descriptor web.xml, the ressource's reference would be the same. You wouldn't have to change this reference in the java source :
<resource-ref>
<res-ref-name>url/environment</res-ref-name>
<res-type>java.net.URL</res-type>
<res-auth>Application</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
Then use this ressource to read the properties.
try {
Context l_ctx = new InitialContext();
URL l_url = (URL) l_ctx.lookup("java:comp/env/url/environment");
// New properties
Properties l_properties = new Properties();
// Load properties
this.loadProps(l_properties, l_url.getPath());
} catch (NamingException e1) {
// TODO
e1.printStackTrace();
} catch (IOException e) {
// TODO Bloc catch auto-généré
e.printStackTrace();
}
...
private void loadProps(final Properties p_properties, final String p_fileLocation)
throws IOException
{
// Open stream
BufferedInputStream l_is = new BufferedInputStream(
new FileInputStream(
new File(p_fileLocation)));
p_properties.load(l_is);
// Close stream
l_is.close();
}
You will need to bind the ressource reference url/environment of the web.xml to the JNDI name url/environmentJndiName set for this ressource on the websphere server. Modify the ibm-web-bnd.xml file with websphere, the sun-web.xml file with glassfish, etc.
THANKS
If there is a better solution, or if it does not answer the question, let me know. I am still learning but I have been working with websphere for a while - even if I prefer other solutions. Thanks, #+.
I have small program which just creating intial context in unmanaged environment i.e. outside the container.I have been using Websphere 7.0.
I have written following program to do the connection with application which is running on WAS 7 using corba url,
package snippet;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
public class test {
public static void main(String[] args) {
try {
// create initial context
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.websphere.naming.WsnInitialContextFactory");
env
.put(Context.PROVIDER_URL,
"corbaloc:iiop:1.0#x1devapp63.dev.freightliner.com:2809/NameService");
InitialContext ctx = new InitialContext(env);
System.out.println(ctx);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I have created runnable jar and executing using shell script given below,
#!/bin/sh
WAS_ROOT_PATH=/application/WebSphere/AppServer
SCHEDULER_JAR=/application/apps/JobScheduler/testJNDI.jar
SCHEDULE_FILE=/application/apps/JobScheduler/schedule.xml
. "$WAS_ROOT_PATH"/bin/setupCmdLine.sh
CLASSPATH="$MQLIB":"$WAS_CLASSPATH"
"$JAVA_HOME"/bin/java -classpath "$CLASSPATH" -jar "$SCHEDULER_JAR"
Ater running i have been facing below exception,
$ testJNDI.sh
javax.naming.NoInitialContextException: Failed to create InitialContext using factory specified in hashtable {java.naming.provider.url=corbaloc:iiop:1.0#x1devapp63.dev.freightliner.com:2809/NameService, java.naming.factory.initial=com.ibm.websphere.naming.WsnInitialContextFactory} [Root exception is java.lang.NullPointerException]
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:243)
at javax.naming.InitialContext.initializeDefaultInitCtx(InitialContext.java:327)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:357)
at javax.naming.InitialContext.internalInit(InitialContext.java:295)
at javax.naming.InitialContext.<init>(InitialContext.java:212)
at snippet.test.main(test.java:19)
Caused by: java.lang.NullPointerException
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:235)
... 5 more
$
I got stuck on above problem but i could not get why this is happening.
Please do the needful to get out me from above problem.
Don't forget to include the thinclient-jars to your buildpath.
You will need them to do a jndi lookup from a standalone client.
%WAS_HOME%/runtimes is where they can be found.
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.nd.multiplatform.doc/info/ae/ae/ccli_standaloneclient.html
The Provider URL helps you to identify the server and the root # which you connect to the name space.
As an example, if you wanted to connect to the Cell Persisent root, you would specify the the Provider_URL as:
env.put(Context.PROVIDER_URL,
"corbaloc:iiop:myhost.mycompany.com:2809/NameServiceCellPersistentRoot");
Server Root NameServiceServerRoot
Cell Persistent Root NameServiceCellPersistentRoot
Cell Root NameServiceCellRoot
Node Root NameServiceNodeRoot
The default object key is:"NameService" so stating that in the URL is not required if you want to connect to the default location.
Also, is there anything else in the stack trace that states any other information?
Also from the client machine is the DNS name: x1devapp63.dev.freightliner.com resolvable?
Is this the name that is used by the WAS Server to identify itself? When WAS is installed you do specify a host name and does that match this name?
Can you also run the same from the same machine as the WAS Server and use localhost and see if the errors are the same.
I am just thinking about potential network related errors which are probably causing trouble.
Have a look at this for the various values that help you could connect to for the root context.
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.nd.multiplatform.doc/info/ae/ae/rnam_example_prop5.html
HTH
Manglu
Are you sure the provider URL is correct? According to various examples like this one (WAS Express 6) or this one (WAS 8) (couldn't find a reference for WAS 7 but it looks like things didn't change), the code to use a CORBA object URL with the WAS JNDI implementation is described as follows:
Using a CORBA object URL
This example shows a CORBA object URL.
...
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
...
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.websphere.naming.WsnInitialContextFactory");
env.put(Context.PROVIDER_URL, "corbaloc:iiop:myhost.mycompany.com:2809");
Context initialContext = new InitialContext(env);
...
Don't know if this will help though.
Tomcat offers a build in "Virtual Hosting" Support: An Engine/Web-Application can be configured to be responsible for a list of Domains. These Domains have to be put into the server.xml/context.xml files with a special xml directive.
=> Is there any possibility to change the Tomcat Configuration (in general) and especially the "Virtual Hosts" of a Web-Application/Engine programmatically?
For example if a new user signs up, I have to add his domain to the list of "accepted virtual hosts/domains". The only way I currently think of is changing the xml files via a script and then restart Tomcat.
Is there any way to add them add runtime via some Java-Methods programmatically?
Thank you very much!
Jan
Tomcat provides APIs to create new virtual host. To get access to the wrapper object needed for this, you need to implement a ContainerServlet. You can create virtual host like this,
Context context = (Context) wrapper.getParent();
Host currentHost = (Host) context.getParent();
Engine engine = (Engine) currentHost.getParent();
StandardHost host = new StandardHost();
host.setAppBase(appBase);
host.setName(domainName);
engine.addChild(host);
You need to make sure appBase directory exist and you have to find ways to persist the new host to the server.xml or you lose the host on restart.
However, this approach rarely works. If your users run their own apps, you really want run separate instances of Tomcat so you can sandbox the apps better. e.g. One app running out of memory doesn't kill all other apps.
If you provide the app, you can just use one host (defaultHost). You can get the domain name from Host header and do whatever domain-specific stuff in your code.
You shouldn't change the server environment programmatically and there are no reliable and standard ways to do this. Best is to do and keep it all on the webapp side. To start, a Filter is perfectly suitable for this. Store the names somewhere in a database table or a properties file which you cache in the application scope. Check the HttpServletRequest#getRequestURI() (or the getServerName() if it is a subdomain instead of pathinfo) and do the forwarding task accordingly.
Hope this helps.
Use JMX
ArrayList serverList = MBeanServerFactory.findMBeanServer(null);
MBeanServer server = (MBeanServer) serverList.get(0);
Object[] params = { "org.apache.catalina.core.StandardHost", hostName };
String[] signature = { "java.lang.String", "java.lang.String" };
server.invoke(new ObjectName("Catalina:type=Engine"), "addChild", params, signature);
If needed, retrieve the host object and work with it:
ObjectName host = new ObjectName("Catalina:type=Host,host=" + hostName);
server.setAttribute(host, new Attribute("autoDeploy", false));
server.invoke(host, "start", null, null);
I would suggest you set your application to be the default virtual host in server.xml so your single virtual host can respond to requests addressed to any host name. Tomcat ships with the localhost application set as the default virtual host. So you can see how to do this by simply inspecting the server.xml file of a vanilla tomcat installation. You can programatically determine the host name the user sent the request to using the ServletRequest.getServerName() method.
Tomcat used to ship with a web application called "host-manager". Note: this is different than the "manager" web application that still comes with Tomcat. Host manager allowed for changing configuration or adding new virtual hosts on the fly without restarting the server. You could interact with the host-manager over HTTP (programmatically if desired). However, it had the unfortunate flaw of not committing its changes to server.xml so they were all lost on a web server restart. For whatever reason, starting with version 6, Tomcat no longer ships with the host-manager application. So it doesn't appear to be supported anymore.
To sum up ZZ Coder answer which guided me a lot:
You have to create a servlet that implements ContainerServlet and override setWrapper method to get the org.apache.catalina.Wrapper object.
For doing that you have to have privileged="true" in your context.xml Context tag or it will throw an exception. Then you can use the Wrapper object and:
StandardContext context = (StandardContext) wrapper.getParent();
StandardHost currentHost = (StandardHost) context.getParent();
StandardEngine engine = (StandardEngine) currentHost.getParent();
StandardHost host = new StandardHost();
host.setAppBase(currentHost.getAppBase()); //in my case I created another instance of the same application
host.setDomain(currentHost.getDomain());
host.setAutoDeploy(false); // not restarting app whenever changes happen
host.setName("domain.com");
host.setThrowOnFailure(true);// tell it to throw an exception here if it fails to create the host
host.setDeployOnStartup(true);
host.setStartChildren(true);
host.setParent(engine);
// you can add multiple aliases
host.addAlias(alias);
StandardContext ctx = new StandardContext();
ctx.setDocBase(context.getDocBase()); //again I reused my same application setting
ctx.setPath("");
if(currentHost.getWorkDir() != null)
{//create a working directory based on your new host's name
ctx.setWorkDir(currentHost.getWorkDir().replace(currentHost.getName(), host.getName()));
}
ctx.setName(host.getDomain());
//some extra config that you can use
ctx.setUseHttpOnly(false);
ctx.setReloadable(false);
ctx.setXmlValidation(false);
ctx.setXmlNamespaceAware(false);
ctx.setCrossContext(false);
ctx.setParent(host);
// you have to have this or it will not work!!
ctx.addLifecycleListener(new ContextConfig());
//you can also create resources and add it to the context like so:
final ContextResource res = new ContextResource();
res.setName("name");
res.setAuth("Container");
res.setType("javax.sql.DataSource");
ctx.getNamingResources().addResource(res);
host.addChild(ctx);
engine.addChild(host);
You can add properties to your resource by calling res.setProperty("name", "value")
Some properties that you can use are:
initialSize,maxTotal,maxIdle,maxWaitMillis,removeAbandonedOnBorrow,removeAbandonedTimeout,validationQuery,timeBetweenEvictionRunsMillis,driverClassName,url,username,password.
Another exciting thing to is to get the host from the tomcat engine by calling engine.findChild(domain) and use stop(), start(), getStateName() and have your own Tomcat Admin panel!