Have you noticed new feature "Working Set.." in designer 8.5? It's certainly a new feature for those who didn't work in Eclipse editor.
Lets first check why it's widely used in Eclipse editor.While working in Java project there are fair chances when your project contains hundred of classes and packages. What if when you need to find whether your fellow team member has worked on Database connection class or not.Will you go through each classes to find those methods ? To overcome such situation Eclipse added "Working Set.." functionality.
Working sets are a concept derived to help the developer categorize resources across projects into a contextually relevant representation. At its core, working sets are simply, as their name suggests, a sub-set of files/classes/folders/projects that represent a certain developer workflow. At the simplest level, working sets can be a way to categorize multiple projects together that may represent a single application. Developers aren't restricted to using working sets at the project level, however. It is possible to select particular packages, classes, and folder structures to be included or excluded from a given working set. This allows developers to organize code anyway they want.For an example, Here is my test project list in Eclipse.
I want to know how many places I've used DateTime class. To do so , Go to "Working Set" option from "Search" menu,
Created new "Working Set",
Give a name and choose projects where you wish to perform search,
Select DateTime word ,select working sets and click OK
Here is your result,
So,You've seen Working sets group elements for display in views or for operations on a set of elements. Now lets check in Domino designer,
First create new working set and perform search. You can choose design elements while creating "Working set".
Here is result for search word which is used in my Agent and Script libraries.
However I'm experiencing some gotcha in using "Working Set.." in edit mode of design element. Let's assume, I've a function called "GetQueryStringvariable" and I'm willing to check occurrence of this function in multiple nsfs.I've opened my script library , selected the word and tried search in my newly created working set. I get following dialog box,
I was expected this to work like Eclipse editor (which I've shown above) but don't know whether it's designed like that or I'm wrong somewhere.However I can achieve this in other way by using Search->Search
Here is the result,
It's a great feature which can provide similar functionality which is there in "TeamStudio" like searching how many database you've hard coded server name and database name etc etc..
It's quite common to use embedded view in notes application but many of Lotus Notes developers don't find easy and efficient for web based application.I was going through Notes/Domino 6 and 7 Forum and found similar problem to one of the developer. She wanted to display a combobox (which refers to docs in a view on the database) to show only selected docs in an embedded view. e.g. category = "Finance".
http://www-10.lotus.com/ldd/nd6forum.nsf/DateAllThreadedweb/b03202c47143f47b8525761e0067fe74?OpenDocument
She didn't got satisfactory answer so created another post saying , She wanted to refresh an embedded view based on the value of a combobox on the web.
http://www-10.lotus.com/ldd/nd6forum.nsf/DateAllThreadedweb/66a335842154b86c8525761f0060073b?OpenDocument
So question is why should we use embedded view in web based application ? , Does it really required ? Can't we achieve similar functionality using ajax ? Don't you think we should break the trend which was started in Notes 5 era ?
Actually I never used embedded view in any of my web applications.I prefer AJAX instead of embedding view because it's fast and interacting well to the end user.
Let's have a look to simple requirement where you've to provide List box to the user where he can select multiple orders and can view their details. There could be many ways to achieve this but what could be the elegant way to make users WOW .. It's AJAX.
Here is the sample,
Here are simple steps to get rid of embedded views in web applications,
Step 1: Create a single column lookup view with following column formula,
orderNo + "|" + @Text(@DocumentUniqueID) |
Step 2: Write dbcolumn in combo box to populate order numbers.
Step 3: On "View Order" button click write JavaScript to retrieve Document UNID and pass them to AJAX function.
//-------------------------------------------------------------------------------- var orderID=""; var sep=""; for(i=0; i<=document.forms[0].OrderSelection.length-1; i++) { if ( document.forms[0].OrderSelection.options[i].selected ) { orderID = orderID +sep+document.forms[0].OrderSelection.options[i].value; sep="^"; } } displayOrder(orderID); //-------------------------------------------------------------------------------- function displayOrder(orderID){ url= location.href; tmpurl = url.substring(0,url.indexOf(".nsf")) agentUrl= tmpurl+".nsf"+"/displayOrder?OpenAgent" argsParam=trim(orderID); runAgent(agentUrl,argsParam); } //-------------------------------------------------------------------------------- function runAgent(agentUrl,argsParam) { req = false; if (window.XMLHttpRequest) { try { req = new XMLHttpRequest(); } catch(e) { req = false; } } else if(window.ActiveXObject) { try { req = new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) { try { req = new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) { req = false; } } } if (req ) { req.onreadystatechange = processReqChange; req.open("POST", agentUrl, true); req.send(argsParam); } } //---------------------------------------------------------------------------------- function trim(str) { return str.replace(/^\s+|\s+$/g, ''); } //---------------------------------------------------------------------------------- function processReqChange() { if (req.readyState == 4) { if (req.status == 200) { document.getElementById("status").style.display="none" ; xmlStr=req.responseText if ( xmlStr == 0 ) { document.getElementById("status").innerHTML="Error in retrieving order"; return false; } else { document.getElementById("Contents").innerHTML=xmlStr; } } else {alert("There was a problem retrieving the XML data:\n" + req.statusText);} } } //----------------------------------------------------------------------------------- |
Step 5: In your Lotus Script agent use "Request_Content" CGI method to retrieve POST arguments. Write your business logic , Build custom HTML and return them using Print method.Don't forget to set content-type as per your logic ( Text, HTML or XML ). Code can be,
There are best ways to design Lotus Notes applications robust and as powerful as dot net and Java, Don't let others say "Notes systems are ugly".It's just our efforts which can lead Notes market as high as It was 10 years ago..
Just saw new design of Ideajam home page but not as good as it was before . Most of the frequently used components like Search, login and What's hot is moved down and to access them you need to scroll :(. I personally believe most used components should be quickly accessible and visible to end users at a glance.Also, Hot ideas and tags section should be above to Ideajam information section.
My vote goes to the old one ,
Recently I've got a requirement to build address picker for web application which uses Active directory.I've spend couple of hours on net to find some sample application/code but no success. Even though I had implemented ActiveX and JNDI based program which search users in Active directory but those were for Notes client based application.
After some case study , I came to know only solution is to write Java Servlet to connect Active directory and build address picker on the web.After reading some Servlet tutorial and Notes help file got some confidence in writing Servlet in Domino application.I must say, It was quite easy and fun to write Servlet program.Here is my address picker which works perfectly in IE and Firefox allowing multiple users selection.
Let's start some postmortem on the code. First check my core logic to connect LDAP and retrieve records.Probably it's same as which I've posted in my last blog
In above code, I'm looping through each person records in Active Directory and writing in the list box using PrintWriter class.
Now lets check the code in very simple steps.
Step 1: You need following classes to be imported in your agent,
import java.io.*; // For PrintWriter class import javax.servlet.*; // For Servlets class import javax.servlet.http.*; // For Servlets class import lotus.domino.*; // For Domino class import java.util.*; // For util import javax.naming.*; // For JNDI import javax.naming.directory.*; // For JNDI |
Step 2: Construct basic skeleton to write Java class.
public class namePicker extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{ try { // Code goes here }catch (NotesException n) { System.out.println("Exception ID: " + n.id); System.out.println("Exception description: " + n.text); } finally { NotesThread.stermThread(); } } } |
Above code extends a Java interface called HttpServlet.Inside the code, there are a few predefined methods you want to override, for example, here doGet() method gets called with HttpServletRequest object and HttpServletResponse object as parameters. The HttpServletRequest is a java object that is created by the container and captures an incoming HTTP request in an object form.HttpServletResponse provide HTTP-specific functionality in sending a response. For example, it has methods to access HTTP headers and cookies.
Step 3: Using setContentType method to sets the content type which will be sent to the client.Next, Creating PrintWriter object from getWriter method of HttpServletResponse class.This class is used to write contents on the browser.
res.setContentType("text/html"); PrintWriter printOnBrowser = res.getWriter(); |
So our code will be ,
public class namePicker extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{ res.setContentType("text/html"); PrintWriter printOnBrowser = res.getWriter(); try { //codes goes here }catch (NotesException n) { System.out.println("Exception ID: " + n.id); System.out.println("Exception description: " + n.text); } finally { NotesThread.stermThread(); } } } |
Step 4: Now we need to create NotesThread and initialize Domino session. To do so,
NotesThread.sinitThread(); Session session = NotesFactory.createSession(); |
Using sinitThread() method of NotesThread class and NotesFactory class to creation Notes session. Check designer help to get more idea.So our code changed to,
public class namePicker extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{ res.setContentType("text/html"); PrintWriter printOnBrowser = res.getWriter(); try { NotesThread.sinitThread(); Session session = NotesFactory.createSession(); }catch (NotesException n) { System.out.println("Exception ID: " + n.id); System.out.println("Exception description: " + n.text); } finally { NotesThread.stermThread(); } } } |
Step 4: Now you're well set to write HTML and JavaScript in Servlet which will be printed on browser like Lotus Script "Print" statement. Something like,
Step 5 At the end don't forget to destroy Domino objects which you've created because we are using Multi threaded programming , mistakes can screw your Domino server. To destroy Domino objects, User recycle()
session.recycle(); |
How I'm calling my Servlet from Domino
window.open( '/servlet/namePicker','newWin', 'toolbar=no,location=no,directories=no,status=no,menubar=no, scrollbars=no,resizable=no,width=540,height=340') ; |
Note that I'm referring "Servlet" folder from my server directory which is in (Lotus\Domino\data\domino\servlet)
Full Servlet code can't be posted here because lack of HTML support on this site.If anyone interested in getting full code ,drop me an e-mail.Along with that I've done similar name picker which use NAB using Servlet.Hopefully soon both sets of code will be posted in OpenNTF.
Hope this article can be useful to those who wish to integrate Domino with third party application using Java Servlet.
Oops, Forgot to mentioned some links for those who are not sure how to run Servlet in Domino, there is some gotcha in that :). You may follow Jake's article ,
Creating servlets inside the Domino Designer
Java servlets: Extending your Domino applications
Only thing is changed from Jake's article about adding ,jsdk.jar in your agent . You don't need to do any more ( at least with Designer 8.5 )
To continue with my small but useful findings in Domino designer 8.5. Few months back I've found really nice implementation in 8.5 designer but forgot to mention it.
While working on domino designer many of us open up lots of design elements and database in left navigation. What happens when you realize you don't need to work anymore on that database and you wish to remove bookmark.Though ,if you've opened up lots of design elements of that database you must need to close one by one in order to remove the bookmark of that database. It was really a pain in previous version of designer but no more with Domino designer 8.5 (not sure about 8.0).
In Domino 8.5 designer if you remove database bookmark from left navigation it correspondingly removes every single opened design elements tab from current perspective. Thanks to designer team who is working so hard to implement small but really important feature.
Now let's talk about my second finding,When we create new agent or script library in older version of designer does it checks whether any agent or script library already exist with the same name ? I guess no , mostly it creates design element with same name ( or may be with "copyof...." name ). In Domino designer 8.5 , It checks before creating new agent or script library and accordingly throws an error if you try to create with existing name.AWESOME...
However,It is strange that same validation doesn't work for Form,
It's Probably a feature ( can't say bug ) for Agents and Script libraries.When there is a similar pop-ups for creating Agent/Form , then in-line validation should work even same way.I believe it should be uniformed. Any thoughts ?
It seems I'm more productive on Friday :) just kidding. When you rename agent in agent property window it doesn't get updated in-line, I mean as soon as you finish typing . Furthermore you need to save and close the agent then only you can see the changes in agent name. Let's see what I'm blubbering.
Let's first open existing form ,
Do some changes in Form name and hit enter,
As soon as you hit enter you can see the changes taken effect and a star appears which shows you've not saved your form. Thanks to IBM for small but very useful feature.
Let's do same for an Agent , Open any existing agent
Do some changes in agent name box and hit enter,
You can see star appears but name hasn't change. No matter how many times you change the name and hit enter it remains same as it was when opened.
Furthermore , Now save your agent but don't close it and notice can you see the new name ?
If you notice , name has changed in agent list in left navigation but still old name is appearing in agent tab until you close and reopen the agent.
So , What do you say , Is it a bug ?
Have you ever annoyed in tweaking between two design elements while working on same or different database simultaneously in Domino designer? Let's assume I've a form with complex design and I need to write agent or script library or even need to design view based on the form . What actually we do ? We keep tweaking between design elements and doing development . Today I found R8.5 Designer has given something I silently wished always. With designer 8.5 you don't need to do any more , You can adjust one design element at the top and other at the bottom and can work simultaneously without losing your attention.
Here what we used to do in previous versions of designer,
Now with 8.5 designer ,
Designer 8.5 , I'm loving it... Finger licking good.... :)
Today It's very common in most of the companies to have Microsoft Active Directory and Lotus Notes implementation together. We also use Active Directory and Lotus Notes side by side to validate Lotus Notes and SharePoint applications. Recently I've got a requirement to query Active Directory based on users profile which resides in our Lotus Notes view. I've implemented two sets of code one using Domino Java and jndi and other using Lotus Script. I've written Lotus script to those who are good in Lotus scripting and willing to perform such kind of cross implementation.By seeing the code you may realize how simple is to query Active directory from Domino using Lotus Scripting.To see the Lotus Script code , you may need to wait until it get published in Search Domino since it's already in process.So let's talk about Domino Java+JNDI.
In order to implement this code , You must need to know your Active Directory server name ( or IP address ) and make sure the port number where server is listening.
This code can be further extended to synchronized Lotus Notes address book contents in Active Directory or vice versa . Even it can be used to build Lotus Notes application which can use Active Directory for authentication.
To accomplish this, I'm using JNDI ( The Java Naming and Directory Interface ) which is an API specified in Java technology that provides naming and directory functionality to applications written in the Java programming language. It is designed especially for the Java platform using Java's object model. Using JNDI, applications based on Java technology can store and retrieve named Java objects of any type. In addition, JNDI provides methods for performing standard directory operations, such as associating attributes with objects and searching for objects using their attributes.
To start with the code ,
Step one: Include JNDI API package in your domino Java agent,
import javax.naming.*; |
Step two:
JNDI applications need a way to communicate various preferences and information that define the environment in which naming and directory services are accessed.The following code creates an environment consisting of two security-related properties and creates an initial context using that environment.
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); //Replace with actual server name and port number env.put(Context.PROVIDER_URL, "ldap://serverName:389"); env.put(Context.SECURITY_PRINCIPAL, "CN=Rishi Sahi/OU=Development/O=Home"); env.put(Context.SECURITY_CREDENTIALS, "Password goes here"); DirContext ctx = new InitialDirContext(env); |
Step 3: Build a search scope , You need to define Active directory attributes which are going to be searched,
String[] attrIDs = {"cn","uid"}; SearchControls ctls = new SearchControls(); ctls.setReturningAttributes(attrIDs); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); |
In above code , SearchControls class encapsulates factors that determine scope of search and what gets returned as a result of the search.Next,setReturningAttributes() method specifies the attributes that will be returned as part of the search and setSearchScope() to SUBTREE_SCOPE to search the entire subtree rooted at the named object.
Step 4: Using search method of DirContext.It searches in a single context for objects that contain a specified set of attributes, and retrieves selected attributes. Note that my first argument is blank which make it search in entire scope, you can even define specific root.At the end make sure your results stored in NamingEnumeration type object.
String filter = "cn="+ searchUser; NamingEnumeration answer = ctx.search("", filter,ctls); |
Step 5: In the last step only you need to loop through your search results and retrieve attributes value.
while (answer.hasMore()) { SearchResult sr = (SearchResult)answer.next(); System.out.println("<<" + sr.getName()+">>"); Attributes attrs = sr.getAttributes(); System.out.println(attrs.get("cn").get()); isFound="1"; } |
Here is the complete code,
import javax.naming.*; import javax.naming.directory.*; import java.util.*; public class LDAPQuery { public static void ldapconnect(){ String searchUser="Rishi Sahi"; String isFound="0"; try { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://serverName:389"); //Replace with actual server name and port number env.put(Context.SECURITY_PRINCIPAL, "CN=Rishi Sahi/OU=Development/O=Home"); env.put(Context.SECURITY_CREDENTIALS, "Password goes here"); // Create initial context DirContext ctx = new InitialDirContext(env); // Specify the ids of the attributes to return String[] attrIDs = {"cn","uid"}; SearchControls ctls = new SearchControls(); ctls.setReturningAttributes(attrIDs); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); String filter = "cn="+ searchUser; // Search for objects that have those matching attributes NamingEnumeration answer = ctx.search("", filter,ctls); try { while (answer.hasMore()) { SearchResult sr = (SearchResult)answer.next(); System.out.println("<<" + sr.getName()+">>"); Attributes attrs = sr.getAttributes(); System.out.println(attrs.get("cn").get()); isFound="1"; } if ( isFound=="1") { System.out.println("User found in Active Directory!"); } else { System.out.println("Opps ! User not found in Active Directory!"); } answer.close(); }catch(PartialResultException e) { e.printStackTrace(); } // Close the context when we're done ctx.close(); } catch (Exception e) { e.printStackTrace(); } } public LDAPQuery() { // Don't think I'm doing anything here } } |
To call this routine,
import lotus.domino.*; public class JavaAgent extends AgentBase { public void NotesMain() { try { Session session = getSession(); AgentContext agentContext = session.getAgentContext(); LDAPQuery objQuery = new LDAPQuery(); objQuery.ldapconnect(); } catch(Exception e) {e.printStackTrace();} } } |
Reference : Java Naming and Directory Interface
So thought of the day
"I love Lotus Notes because I don't see anything which is not possible in Domino."