I am trying to place an object in JNDI, so that only one of the progam should be able to place it in JNDI. is there any global lock that can be used in J2EE environment. Is RMI can be used for this purpose? please provide any reference links. Thanks in advance.
Also, what is NameAlreadyBoundexception? I am trying to use it as a method to synchronize, i.e, only one program places it in JNDI and if other trying to bind should get that exception.
But when i am testing the multiple binding I am not getting the Exception.And second binding is done. look up is giving the second object bound. here is my code:
public class TestJNDI {
private static String JNDI_NAME = "java:comp/env/test/something";
public static void main(String[] args) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
env.put(Context.PROVIDER_URL,"t3://127.0.0.1:7001");
Context ctx = new InitialContext(env);
System.out.println("Initial Context created");
String obj1 = "obj1";
String obj2 = "obj2";
try{
ctx.bind(JNDI_NAME, obj1);
System.out.println("Bind Sucess");
}catch(NameAlreadyBoundException ne ){
// already bound
System.out.println("Name already bound");
}
ctx.close();
Context ctx2 = new InitialContext(env);
try{
// Second binding to the same name not giving the Exception??
ctx2.bind(JNDI_NAME, obj2);
System.out.println("Re Bind Sucess");
}catch(NameAlreadyBoundException ne ){
// already bound
System.out.println("Name already bound");
}
String lookedUp = (String) ctx2.lookup(JNDI_NAME);
System.out.println("LookedUp Object"+lookedUp);
ctx2.close();
}
}
When you close the first content ctx1 you release any objects bound to it see : Context
So your second context has nothing to do with the first one.
Related
I followed this tutorial to search in active directory.
Sample code :
class SearchSubtree {
public static void main(String[] args) {
Hashtable<String, Object> env = new Hashtable<String, Object>(11);
env
.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
try {
DirContext ctx = new InitialDirContext(env);
String[] attrIDs = { "sn", "telephonenumber", "golfhandicap", "mail" };
SearchControls ctls = new SearchControls();
ctls.setReturningAttributes(attrIDs);
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String filter = "(&(sn=Geisel)(mail=*))";
NamingEnumeration answer = ctx.search("", filter, ctls);
// Print the answer
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
But NameNotFoundException is thrown at
NamingEnumeration answer = ctx.search("", filter, ctls);
But when I pass, "DC=extldap,DC=com" as first argument, code works fine.
Is there any issue with the tutorial? Can first argument not be empty string? Or is this a limitation with Active Directory?
Generally speaking, for LDAP servers you always need a root context to start your search from. Basically, you are doing the equivalent of trying to search a SQL database without specifying a database or table name.
Some server implementations may allow an empty context (I know iPlanet used to allow it in some cases) but these are exceptions to the rule.
The javadoc for DirContext.search() says:
Searches in the named context or object for entries that satisfy the
given search filter. Performs the search as specified by the search
controls.
See search(Name, String, SearchControls) for details.
Parameters:
name the name of the context or object to search
...
Usually, in Active Directory it is fine to start searching from the domain root, which is always DC=<your>,DC=<domain>.
That is why your second search works.
i need some help. I have to retrieve whole jndi db options to a selectlist in a html file which means i need to access all jndi db names and get these values
Any idea ?
I had some trouble finding JNDI names in one of my WebLogic servers. I created a method that iterates through the JDNI tree structure, and prints all of them to the console. I am not sure that this is what you need, but here is the code I used for it:
private void printList(String directory){
try {
NamingEnumeration<NameClassPair> namings = context.list(directory);
System.out.println("************Printing " + directory + "**************");
while(namings.hasMoreElements()){
if(directory.equals("")) printList(namings.next().getName());
else printList(directory+"."+namings.next().getName());
}
System.out.println("Done printing " + directory);
} catch (NamingException e) {
// TODO Auto-generated catch block
System.out.println(directory);
}
}
you can pass a string of a desired directory, or an empty string, if you want all elements from the root. You'll need to import javax.naming.* (or -NamingEnumeration/-NameClassPair)
Almost forgot:
you'll first need to define a context for where the method should look for the directory:
Context context = null;
Hashtable<String, String> ht = new Hashtable<String, String>();
ht.put(Context.PROVIDER_URL, "your_host");
ht.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
//this above needs to be changed to fit your desired system
ht.put(Context.SECURITY_PRINCIPAL, "your_user");
ht.put(Context.SECURITY_CREDENTIALS, "your_password");
try {
context = new InitialContext(ht);
// Use the context in your program
}
catch (NamingException e) {
e.printStackTrace();
}
I'm pretty sure i know the problem, I just don't know how to solve it.
I have a java EE application that do searches in ldap. I initialize the context with getEnv :
(note* : code is a bit simplified for understanding purposes)
InitialDirContext ctx = new InitialDirContext( getEnv( CONFIG_MAP ); //CONFIG_MAP contains the host, mng_dn, mng_pw
public static Hashtable<String, String> getEnv( Map<String, String> configMap ) {
// Hashtable for environmental information
Hashtable<String, String> env = new Hashtable<String, String>();
// Specify which class to use for our JNDI Provider
env.put( Context.INITIAL_CONTEXT_FACTORY, INITCTX );
// Specify the host and port to use for directory service
env.put( Context.PROVIDER_URL, configMap.get( HOST ) );
// Security Information
env.put( Context.SECURITY_AUTHENTICATION, "simple" );
env.put( Context.SECURITY_PRINCIPAL, configMap.get( MGR_DN ) );
env.put( Context.SECURITY_CREDENTIALS, configMap.get( MGR_PW ) );
env.put( "java.naming.ldap.attributes.binary", "objectSID" );
return env;
}
I don't know if this was bad practice but to prevent the initialization from happening before every search I did an Init function that does :
if(Util.ctx == null ){
Util.init()
}
So the problem comes from here. My application will work roughly 30 mins (not sure of the time) and then the searches won't work anymore and I'll get the connection reset error in my console. My guess is that the connection is "closed" and it's not doing the initialization again since ctx is not null. I need help to figure out what to add to my if statement in order to prevent this error from happening. Maybe something like
if(Util.ctx == null || Util.ctx.isClosed() ){
Util.init();
}
I read on InitialDirContext and couldn't find what I need.
Don't try to keep reusing the same Context. Get a new one every time you need one. The server will close idle connections any time it feels like it, and isClosed() won't tell you when it has done so.
You can use the JNDI LDAP connection pooling feature to conserve connections.
What about set no timeout as follows:
// Set up environment for creating initial context
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
// Specify time-out to be infinite time . make it like never expired
env.put("com.sun.jndi.ldap.connect.timeout", "-1");
// Create initial context
DirContext ctx = new InitialDirContext(env);
And you can close it later when needed as follows:
finally {
if (obj instanceof Context) {
Context ctx = (Context) obj;
try {
ctx.close();
}
catch (Exception e) {
}
}
}
Check this out:
https://docs.oracle.com/javase/tutorial/jndi/newstuff/readtimeout.html
I am trying to take a very long file of strings and convert it to an XML according to a schema I was given. I used jaxB to create classes from that schema. Since the file is very large I created a thread pool to improve the performance but since then it only processes one line of the file and marshalls it to the XML file, per thread.
Below is my home class where I read from the file. Each line is a record of a transaction, for every new user encountered a list is made to store all of that users transactions and each list is put into a HashMap. I made it a ConcurrentHashMap because multiple threads will work on the map simultaneously, is this the correct thing to do?
After the lists are created a thread is made for each user. Each thread runs the method ProcessCommands below and receives from home the list of transactions for its user.
public class home{
public static File XMLFile = new File("LogFile.xml");
Map<String,List<String>> UserMap= new ConcurrentHashMap<String,List<String>>();
String[] UserNames = new String[5000];
int numberOfUsers = 0;
try{
BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
String line;
while ((line = reader.readLine()) != null)
{
parsed = line.split(",|\\s+");
if(!parsed[2].equals("./testLOG")){
if(Utilities.checkUserExists(parsed[2], UserNames) == false){ //User does not already exist
System.out.println("New User: " + parsed[2]);
UserMap.put(parsed[2],new ArrayList<String>()); //Create list of transactions for new user
UserMap.get(parsed[2]).add(line); //Add First Item to new list
UserNames[numberOfUsers] = parsed[2]; //Add new user
numberOfUsers++;
}
else{ //User Already Existed
UserMap.get(parsed[2]).add(line);
}
}
}
reader.close();
} catch (IOException x) {
System.err.println(x);
}
//get start time
long startTime = new Date().getTime();
tCount = numberOfUsers;
ExecutorService threadPool = Executors.newFixedThreadPool(tCount);
for(int i = 0; i < numberOfUsers; i++){
System.out.println("Starting Thread " + i + " for user " + UserNames[i]);
Runnable worker = new ProcessCommands(UserMap.get(UserNames[i]),UserNames[i], XMLfile);
threadPool.execute(worker);
}
threadPool.shutdown();
while(!threadPool.isTerminated()){
}
System.out.println("Finished all threads");
}
Here is the ProcessCommands class. The thread receives the list for its user and creates a marshaller. From what I unserstand marshalling is not thread safe so it is best to create one for each thread, is this the best way to do that?
When I create the marshallers I know that each from (from each thread) will want to access the created file causing conflicts, I used synchronized, is that correct?
As the thread iterates through it's list, each line calls for a certain case. There are a lot so I just made pseudo-cases for clarity. Each case calls the function below.
public class ProcessCommands implements Runnable{
private static final boolean DEBUG = false;
private List<String> list = null;
private String threadName;
private File XMLfile = null;
public Thread myThread;
public ProcessCommands(List<String> list, String threadName, File XMLfile){
this.list = list;
this.threadName = threadName;
this.XMLfile = XMLfile;
}
public void run(){
Date start = null;
int transactionNumber = 0;
String[] parsed = new String[8];
String[] quoteParsed = null;
String[] universalFormatCommand = new String[9];
String userCommand = null;
Connection connection = null;
Statement stmt = null;
Map<String, UserObject> usersMap = null;
Map<String, Stack<BLO>> buyMap = null;
Map<String, Stack<SLO>> sellMap = null;
Map<String, QLO> stockCodeMap = null;
Map<String, BTO> buyTriggerMap = null;
Map<String, STO> sellTriggerMap = null;
Map<String, USO> usersStocksMap = null;
String SQL = null;
int amountToAdd = 0;
int tempDollars = 0;
UserObject tempUO = null;
BLO tempBLO = null;
SLO tempSLO = null;
Stack<BLO> tempStBLO = null;
Stack<SLO> tempStSLO = null;
BTO tempBTO = null;
STO tempSTO = null;
USO tempUSO = null;
QLO tempQLO = null;
String stockCode = null;
String quoteResponse = null;
int usersDollars = 0;
int dollarAmountToBuy = 0;
int dollarAmountToSell = 0;
int numberOfSharesToBuy = 0;
int numberOfSharesToSell = 0;
int quoteStockInDollars = 0;
int shares = 0;
Iterator<String> itr = null;
int transactionCount = list.size();
System.out.println("Starting "+threadName+" - listSize = "+transactionCount);
//UO dollars, reserved
usersMap = new HashMap<String, UserObject>(3); //userName -> UO
//USO shares
usersStocksMap = new HashMap<String, USO>(); //userName+stockCode -> shares
//BLO code, timestamp, dollarAmountToBuy, stockPriceInDollars
buyMap = new HashMap<String, Stack<BLO>>(); //userName -> Stack<BLO>
//SLO code, timestamp, dollarAmountToSell, stockPriceInDollars
sellMap = new HashMap<String, Stack<SLO>>(); //userName -> Stack<SLO>
//BTO code, timestamp, dollarAmountToBuy, stockPriceInDollars
buyTriggerMap = new ConcurrentHashMap<String, BTO>(); //userName+stockCode -> BTO
//STO code, timestamp, dollarAmountToBuy, stockPriceInDollars
sellTriggerMap = new HashMap<String, STO>(); //userName+stockCode -> STO
//QLO timestamp, stockPriceInDollars
stockCodeMap = new HashMap<String, QLO>(); //stockCode -> QLO
//create user object and initialize stacks
usersMap.put(threadName, new UserObject(0, 0));
buyMap.put(threadName, new Stack<BLO>());
sellMap.put(threadName, new Stack<SLO>());
try {
//Marshaller marshaller = getMarshaller();
synchronized (this){
Marshaller marshaller = init.jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.marshal(LogServer.Root,XMLfile);
marshaller.marshal(LogServer.Root,System.out);
}
} catch (JAXBException M) {
M.printStackTrace();
}
Date timing = new Date();
//universalFormatCommand = new String[8];
parsed = new String[8];
//iterate through workload file
itr = this.list.iterator();
while(itr.hasNext()){
userCommand = (String) itr.next();
itr.remove();
parsed = userCommand.split(",|\\s+");
transactionNumber = Integer.parseInt(parsed[0].replaceAll("\\[", "").replaceAll("\\]", ""));
universalFormatCommand = Utilities.FormatCommand(parsed, parsed[0]);
if(transactionNumber % 100 == 0){
System.out.println(this.threadName + " - " +transactionNumber+ " - "+(new Date().getTime() - timing.getTime())/1000);
}
/*System.out.print("UserCommand " +transactionNumber + ": ");
for(int i = 0;i<8;i++)System.out.print(universalFormatCommand[i]+ " ");
System.out.print("\n");*/
//switch for user command
switch (parsed[1].toLowerCase()) {
case "One"
*Do Stuff"
LogServer.create_Log(universalFormatCommand, transactionNumber, CommandType.ADD);
break;
case "Two"
*Do Stuff"
LogServer.create_Log(universalFormatCommand, transactionNumber, CommandType.ADD);
break;
}
}
}
The function create_Log has multiple cases so as before, for clarity I just left one. The case "QUOTE" only calls one object creation function but other other cases can create multiple objects. The type 'log' is a complex XML type that defines all the other object types so in each call to create_Log I create a log type called Root. The class 'log' generated by JaxB included a function to create a list of objects. The statement:
Root.getUserCommandOrQuoteServerOrAccountTransaction().add(quote_QuoteType);
takes the root element I created, creates a list and adds the newly created object 'quote_QuoteType' to that list. Before I added threading this method successfully created a list of as many objects as I wanted then marshalled them. So I'm pretty positive the bit in class 'LogServer' is not the issue. It is something to do with the marshalling and syncronization in the ProcessCommands class above.
public class LogServer{
public static log Root = new log();
public static QuoteServerType Log_Quote(String[] input, int TransactionNumber){
ObjectFactory factory = new ObjectFactory();
QuoteServerType quoteCall = factory.createQuoteServerType();
**Populate the QuoteServerType object called quoteCall**
return quoteCall;
}
public static void create_Log(String[] input, int TransactionNumber, CommandType Command){
System.out.print("TRANSACTION "+TransactionNumber + " is " + Command + ": ");
for(int i = 0; i<input.length;i++) System.out.print(input[i] + " ");
System.out.print("\n");
switch(input[1]){
case "QUOTE":
System.out.print("QUOTE CASE");
QuoteServerType quote_QuoteType = Log_Quote(input,TransactionNumber);
Root.getUserCommandOrQuoteServerOrAccountTransaction().add(quote_QuoteType);
break;
}
}
So you wrote a lot of code, but have you try if it is actually working? After quick look I doubt it. You should test your code logic part by part not going all the way till the end. It seems you are just staring with Java. I would recommend practice first on simple one threaded applications. Sorry if I sound harsh, but I will try to be constructive as well:
Per convention, the classes names are starts with capital letter, variables by small, you do it other way.
You should make a method in you home (Home) class not a put all your code in the static block.
You are reading the whole file to the memory, you do not process it line by line. After the Home is initialized literary whole content of file will be under UserMap variable. If the file is really large you will run out of the heap memory. If you assume large file than you cannot do it and you have to redisign your app to store somewhere partial results. If your file is smaller than memmory you could keep it like that (but you said it is large).
No need for UserNames, the UserMap.containsKey will do the job
Your thread pools size should be in the range of your cores not number of users as you will get thread trashing (if you have blocking operation in your code make tCount = 2*processors if not keep it as number of processors). Once one ProcessCommand finish, the executor will start another one till you finish all and you will be efficiently using all your processor cores.
DO NOT while(!threadPool.isTerminated()), this line will completely consume one processor as it will be constantly checking, call awaitTermination instead
Your ProcessCommand, has view map variables which will only had one entry cause as you said, each will process data from one user.
The synchronized(this) is Process will not work, as each thread will synchronized on different object (different isntance of process).
I believe creating marshaller is thread safe (check it) so no need to synchronization at all
You save your log (whatever it is) before you did actual processing in of the transactions lists
The marshalling will override content of the file with current state of LogServer.Root. If it is shared bettween your proccsCommand (seems so) what is the point in saving it in each thread. Do it once you are finished.
You dont need itr.remove();
The log class (for the ROOT variable !!!) needs to be thread-safe as all the threads will call the operations on it (so the list inside the log class must be concurrent list etc).
And so on.....
I would recommend, to
Start with simple one thread version that actually works.
Deal with processing line by line, (store reasults for each users in differnt file, you can have cache with transactions for recently used users so not to keep writing all the time to the disk (see guava cache)
Process multithreaded each user transaction to your user log objects (again if it is a lot you have to save them to the disk not keep all in memmory).
Write code that combines logs from diiffernt users to create one (again you may want to do it mutithreaded), though it will be mostly IO operations so not much gain and more tricky to do.
Good luck
override cont
I have been stuck at a point for so long. I am trying to authenticate a user from an LDAP directory using LDAP via JNDI, but the code attached below returns nothing for "results" i.e. the search method (marked with **) returns null. I tried to debug the code, but did not understand what exactly is going on behind the "search" function of "DirContext" class. Can anybody help please?
public class Authenticate {
#SuppressWarnings({ "unchecked", "rawtypes", "unused" })
public static void main(String[] args) throws NamingException {
final String ldapAdServer = "ldap://iauth.tum.de:389/cn=someuser,ou=users,ou=data,ou=prod,ou=iauth,dc=tum,dc=de";
final String ldapUsername = "cn=someuser,ou=users,ou=data,ou=prod,ou=iauth,dc=tum,dc=de";
final String ldapPassword = "somepassword";
Hashtable env = new Hashtable();
env.put(Context.SECURITY_AUTHENTICATION, "none");
if(ldapUsername != null) {
env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
}
if(ldapPassword != null) {
env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
}
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapAdServer);
DirContext ctx = new InitialDirContext(env);
NamingEnumeration<SearchResult> results = null;
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
**results = ctx.search("", "(objectClass=Person)", controls);**
while (results.hasMoreElements())
{
SearchResult searchResult = (SearchResult) results.next();
Attributes attributes = searchResult.getAttributes();
Attribute attr = attributes.get("cn");
}
}
}
Since the search method of "DirContext" (marked in **), returns nothing, I can never enter the while loop. Can anybody tell where exactly I am being wrong.
You appear to be searching an Active Directory instance. If that's the case (and even if it's not the issue may be the same), then the problem is not to do with your search code but with the initial setup. In particular, this line is at fault:
env.put(Context.SECURITY_AUTHENTICATION, "none");
Per the documentation, setting SECURITY_AUTHENTICATION to "none" performs an anonymous bind, meaning that to the LDAP directory your search request appears to be coming from an anonymous user. By default, Active Directory does not return an error when it gets an anonymous bind request, but the anonymous user does not normally have permissions to search the directory. To ensure that your context is created and bound to the appropriate identity, you should change the line in question to:
env.put(Context.SECURITY_AUTHENTICATION, "simple");
Or even not set the SECURITY_AUTHENTICATION parameter at all, since it defaults to "simple".
Change your filter to "(objectClass=*)" and see, otoh, you are using JNDI not Apache LDAP API like you mentioned in the question.