When I run the following Java code on a Lotus Domino server, I get different results depending on where the code runs.
private void doViewStuff(Session session, PrintStream out) throws NotesException {
Database db = session.getDatabase(null, "myDatabase.nsf");
View view = db.getView("myViewName");
Document doc = view.getFirstDocument();
while (doc != null) {
out.println("doc: " + doc.getUniversalID());
doc = view.getNextDocument(doc);
}
ViewEntryCollection entries = view.getAllEntries();
ViewEntry entry = entries.getFirstEntry();
while (entry != null) {
System.out.println("entry: " + entry.getColumnValues());
entry = entries.getNextEntry(entry);
}
}
When I run the code on the server as a Java agent, there are 37235 documents in the view.
When I run the code in a standalone client, there are only 37217 documents in the view, and the code is much, much slower.
Details and execution environment:
The server version is 8.5.3, the NCSO.jar I used for the client has SHA-1 d879f8992aae49a06769a564217633a9e0fbd1b6.
The database myDatabase.nsf contains about 150000 documents, each with a file attachment.
The missing documents do not appear in a block, they appear between index 10000 and 20000.
In both cases the code runs as the same user account.
What might be the reason that 18 of the documents cannot be found?
Update and Clarification
Upon further inspection, it turned out that I had indeed run the code with different user accounts, and that the inaccessible document had some Reader Names fields.
On the server I had this configuration, although I configured the agent to "Run on behalf of" CN=User Name/O=domain. It didn't matter whether I ran the agent from the Domino Console or via HTTP:
effectiveUserName=CN=User Name/O=domain
commonUserName=domino01
userName=CN=domino01/O=domain
On the client I had this configuration:
effectiveUserName=[NotesException: Not implemented]
commonUserName=User Name
userName=User Name/O=domain
And that was even though I used this code in the client:
Session session = NotesFactory.createSession("127.0.0.1", "User Name", "password");
You say that in both cases the code runs as the same user account, so I want to trust that this is true. I presume, therefore, that you have ruled out Reader Names fields as cause of the discrepancy.
In that case, have you checked the IsValid() property of the ViewEntry objects when you process them in the agent running on the server? Perhaps the NCSO.jar implementation that you are using for the client-side code is filtering out the objects where IsValid() would return false.
Related
I am wondering if there is a way to connect to ldap (389 server) through the apache 2.0.1 java ldap api and then continuously listen for changes to a specific attribute on a set of entries (in this case people with specific qualifications)?
Ideally I would like to run a query on ou=people,dc=test,dc=local
this might initially return
dn: uid=tester1,ou=people,dc=test,dc=local
givenName: tester1
dn: uid=tester2,ou=people,dc=test,dc=local
givenName: tester2
dn: uid=tester3,ou=people,dc=test,dc=local
givenName: tester3
If I then in the background changed tester3's givenName to userTester3 I would like to have a listener that would return some userModified event telling me that tester3 was modified.
As an example of what I would like to happen (psuedo code / non functioning code) I would like to do something along the lines of :
{
PersistentSearch ps = new PersistentSearch();
ps.setChangeType(ChangeType.MODIFY);
SearchRequest sr = ldaputility.createPersistentSearch(qualifiers, attributes, etc, ps);
PersistentSearchListener psl = new PersistentSearchListener(sr){
#Override
public void entryChanged(Entry e){
Log.info("The entry just changed");
}
}
}
There however from what I can tell in the apache 2.0.1 api is not any persistent search listener nor is there any type of listener for search requests in general and the search request gets results and then completes. I know that in the netscape api there is a search listener and that in the apache directory server api there is a persistent search listener. So what I am asking is does anyone know if the apache 2.0.1 ldap api supports a behavior where you make an initial query and any time the results of the query change you can have a listener that is notified of the new changes?
I unfortunately have no debugging code / output since I am not even sure what code to try right now.
It appears that by adding a PersistentSearch control (with changes only set to true and change types set to modifications) to the search request the ldap server won't ever set isDone to true on the search request so then the search request will continue to return the updates as they are available.
Properties props = System.getProperties();
props.put("mail.imap.connectiontimeout",5000);
Session session = Session.getInstance(props);
Store store = session.getStore("imap");
for(50K users){
//login,password changed in loop
String[] folders = {"inbox", "f1", "f2", "f3", "spam"};
store.connect(serverAddress, login + emailSuffix, password);
for (int i = 0; i < folders.length; i++) {
Folder x = store.getFolder(folders[i]);
x.open(Folder.READ_ONLY);
System.out.println("folder " + folders[i] + " of " + login);
x.getUnreadMessageCount();
x.close(false);
}
store.close();
}
I'm using same store for all connections, changed service_count in dovecot according to this answer in order to improve imap-dovecot performance but I see only first iteration and after that code hangs or does next system.out after long time.
Actually, I need to grab all old messages of all users + count all unread messages as I want to migrate from pure Java Mail to some custom format. I didn;t manage even to just iterate over all users and folders for each user because even simple store.connect hangs after 1-st iteration!
I personally think that bottleneck is my dovecot config, but it uses default limits (1000 connections) which looks good.
My I somehow improve my dovecot or connect my store only once for all users or somehow fetch all messages of all users and unreadMessagesCount of all users in other way?
PS. The only alternative to programmatic way is some bash script in maildir which whill read each message from file system and pass it to some rest which converts to my custom format) but it much more harder than Java it's too difficult to parse smptp, parse seen flags from file name and so on.
UPDATE
I found apache commons net imapclient which works very fast.
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
My code is the following
IMAPClient client = new IMAPClient();
client.connect("localhost");
for(50K users){
client.login(login + emailSuffix, password);
for (int i = 0; i < folders.length; i++) {
System.out.println(client.select("INBOX"); //prints true, it's ok
}
}
Looks like it connects faster than java mailapi because it may
connect once to host and after that login for each user. May I somehow repeat such behavior in JavaMail API?
How may I grab messages with apache commons client? All methods return boolean or void, so it's looks like just server checking library am I right? Is it possible to somehow get useful info from imapclient?
Finally solved my problem by simple iterating over file system (I have maildir format).
I guess Java Mail API makes new dovecot auth for each user in store.connect while it should just connect once (consume dovecot auth) and after that login for each user (consume dovecot imap-login). That's why I waited 1 minute for each iteration - it's std idle for auth process in dovecot config. I'm not sure but looks so.
Apache lib works fast but it's just testing library for pinging server, checking connection and other imap operations. It returns boolean result about operations but not useful information(
Background:
We have 4 physical servers (4 IPS), each one running in JBOSS 6 EAP running on port 80.All requests are redirected to any one of these servers via Load balancer.
Now I tried to implement Java cache system for such distributed env so that our properties gets updated in each servers cache.
POC:
For that we did a small POC on our local systems implementing JCS v1.3 lateral caching.
Enabled it in our maven project. The following config is used in .ccf file :
jcs.default=
jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
jcs.default.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache
# PRE-DEFINED CACHE REGION
##############################################################
##### AUXILIARY CACHES
# LTCP AUX CACHE
jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
#jcs.auxiliary.LTCP.attributes.TcpServers=152.144.219.209:8080
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1118
jcs.auxiliary.LTCP.attributes.UdpDiscoveryAddr=228.5.6.8
jcs.auxiliary.LTCP.attributes.UdpDiscoveryPort=6780
jcs.auxiliary.LTCP.attributes.UdpDiscoveryEnabled=true
jcs.auxiliary.LTCP.attributes.Receive=true
jcs.auxiliary.LTCP.attributes.AllowGet=true
jcs.auxiliary.LTCP.attributes.IssueRemoveOnPut=false
jcs.auxiliary.LTCP.attributes.FilterRemoveByHashCode=false
jcs.auxiliary.LTCP.attributes.SocketTimeoOt=1001
jcs.auxiliary.LTCP.attributes.OpenTimeOut=2002
jcs.auxiliary.LTCP.attributes.ZombieQueueMaxSize=2000
And implementing the getter and setter methods for saving a string attribute in cache and getting it from cache
public void addProp(String propId)
throws PimsAppException {
try {
configMSCache.put(propId, propId);
} catch (CacheException e) {
e.printStackTrace();
}
}
#Override
public String testProp(String propId) throws PimsAppException {
if(configMSCache!=null){
return (String) configMSCache.get(propId);
}else{
return "It dint work";
}
}
The application is deployed fine no error in getting it up.
TEST METHOD:
deployed the project.war in my local server and in a remote server with different IP. Both machines are in same network, so no firewall issue in accessing each others IP.
Have saved a property in my server and get it. (Worked fine)
Tried to get the saved property via my local by the remote machine. (It returns blank response).
Means the distributed cache feature is NOT achieved.
Doubts :
1. Does the auxiliary caches set up properly? I mean the configurations
2. Am I testing it properly or how can I test it in dev environment.
3. As JCS UDP Discovery,lets us support the same config on multiple machines, then why it dint work on remote machine?
4. Or is there any caching mechanism, with good examples and documentation can suffice my application needs(as mentioned in background section).
Thanks in advance.
This reply might be too late. But I will suggest in case, to log the stats on both servers and see. As could be possible that it is propagating the cache but just in the processing time, there is an issue reading it.
For example:
JCSAdminBean admin = new JCSAdminBean();
LinkedList linkedList = admin.buildCacheInfo();
ListIterator iterator = linkedList.listIterator();
while (iterator.hasNext()) {
CacheRegionInfo info = (CacheRegionInfo)iterator.next();
CompositeCache compCache = info.getCache();
System.out.println("Cache Name: " + compCache.getCacheName());
System.out.println("Cache Type: " + compCache.getCacheType());
System.out.println("Cache Misses (not found): " + compCache.getMissCountNotFound());
System.out.println("Cache Misses (expired): " + compCache.getMissCountExpired());
System.out.println("Cache Hits (memory): " + compCache.getHitCountRam());
System.out.println("Cache value: " + compCache.get(propId));
}
I have a java-agent from which I can call another agent with the parameter passed through it which contains NoteId, and using that NoteId, I am successfully able to get the work done the that document.Till here every thing is clear.
The main question regarding this is , Is it possible to run the agent of another database on same server from the current database agent?
To be more clear for an example
I have two databases, "ABC.nsf" and "XYZ.nsf", JavaAgent "A" is in "ABC.nsf" and JavaAgent "B" is in "XYZ.nsf". In my xpage I have a button running Agent "A", and even Agent "A" can run any other javaAgent from the same database.
Code:
Document mainDoc = db.getDocumentByUNID(tempDoc.getItemValueString("mainDocId"));
String noteID = mainDoc.getNoteID();
String agentName = "NotificationManager";
Agent agent = db.getAgent(agentName);
if (agent != null)
agent.runOnServer(noteID);
else
System.err.println("Something is wrong");
But Actually I want run the JavaAgent "B" Located in "XYZ.nsf" from JavaAgent "A" which is in "ABC.nsf".
After some research I have referd this code.
Code
Database db=session.getDatabase(current_server, "path/to/XYZ.nsf");
Agent myAgent=db.getAgent("B");
myAgent.run();
And yes I am unsuccessfull there,
Need some idea to acheive this.Any suggession will be really appretiated.
The example code is correct in principle. Just some things you have to know:
First of all the name of server can either be "" or the real name of the server. BUT if there is a server, then you have to check the Trusted servers:- section in the server document (Security Tab - Server Access section). There the server himself has to be member of the field (as name or in a group), otherwise you might not be able to open the other database.
Second thing: the path to the target database is relative to data directory and has to be in the right format for the given operating system.
e.g. C:\IBM\Domino\Data\first\xyz.nsf would be first\xyz.nsf and /local/notesdata/second/abc.nsfwould be second/abc.nsf
Third: the noteid that you get is from a document from the calling database. In the "target"- agent you have to go and get the document from the source database, otherwise it will either throw an error or -as the noteid is just a sequential number- return a document from target database that has nothing to do with the document you are searching for.
The calling agent A would have code like this:
Session session = getSession();
AgentContext agentContext =
session.getAgentContext();
Database dbCurrent = agentContext.getCurrentDatabase();
Database dbTarget = session.getDatabase(dbCurrent.Server, "XYZ.nsf");
Agent myAgent=dbTarget.getAgent("B");
myAgent.runOnServer(noteID);
The called agent B could look like this
Session session = getSession();
AgentContext agentContext =
session.getAgentContext();
Database dbCurrent = agentContext.getCurrentDatabase();
Database dbSource = session.getDatabase(dbCurrent.Server, "ABC.nsf");
Document doc = dbSource.getDocumentByID(agentContext.getCurrentAgent().getParameterDocID())
This should work (if security is ok on the server).
As Paul mentioned in the comments security also means that the agent signer or web user (depending on the settings in agent A) has to have sufficient access to the target database AND the target server (if it is different).
If it does not work despite of correct security: Show us the exact error / trace.
May I suggest a different approach? If you don't need an immediate reply from the agent, as a return value in the code, why don't you send the other database a special mail? Create a mail agent (triggered after new mail has been received), at the sender side create a NotesDocument object, add the values you need to reference the document you want the agent to work on, like the name of the server, the replicaId of the database, and the uniqueId. The agent receives the mail and inspects the fields for what it's supposed to do. The receiving database should be mentioned in the N&A book as Mail-in database.
Advantages are manifold: no hassle with rights, a clear interface, no need to open the other database, the agent is executed by the agent manager at a convenient time, you can easily add more functionality the same way, etc.
I have a section of code within a Web App, running in Tomcat 5.0, that makes a call to the javax.print.PrintServiceLookup method lookupPrintServices(null, null). Previously, this code returned an array of substantial size, listing all the printers on the server as expected. Rather suddenly one day recently, it started behaving differently, now returning a zero-size array of no printers instead. Checking rather thoroughly, I was not able to determine what might have changed to cause this method to behave differently now than it did before.
I made a small, stand-alone test program that contained this same method call.
PrintService[] printers = PrintServiceLookup.lookupPrintServices(null, null);
System.out.println("Java Version: " + System.getProperty("java.version"));
System.out.println("Printers found:");
if (printers != null) {
for (PrintService printer : printers) {
if (printer != null) {
System.out.println(" " + printer.toString());
}
}
}
System.out.println("End");
Running this program, it reacted differently, returning the full list of printers. Double-checking, I put the same code (using logging statements instead of System.print statements) in the context initialization method of the Web App, and it still returns zero printers. The method returns different results depending on whether it is run from the web app war or the stand-alone jar.
Some of my colleagues suggested that it might have to do with the Security Manager, and indeed, the documentation for the PrintService class says that certain properties of a Security Manager can alter results from the method call. However, after adding some code to my test to retrieve and view the Security Manager, it appears that there is none in either case.
try {
if (sec != null) {
System.out.println(sec.toString());
sec.checkPrintJobAccess();
}
System.out.println("*-*-*-*-*Printer Access allowed!!");
}
catch (SecurityException e) {
System.out.println("*-*-*-*-*Printer NOT Access allowed!!");
}
The result is that the Security Manager is null in both cases.
Trying it on a different server, both the web app and the stand-alone jar versions of doing things return no printers. There is no consistency that I can find.
What is going on here? What is causing this javax method call to return different results in different situations? What could have changed about the web app to alter its behavior between one day and the next?
Try starting the server with this option -DUseSunHttpHandler=true to initiate the HTTP URL Connection with JDK API instead of server API.
Hope this works for you too.