Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7019 Articles
Packt
23 Oct 2009
2 min read
Save for later

Network Configuration—Tunneling with Free BSD

Packt
23 Oct 2009
2 min read
Generic Routing Encapsulation (GRE) protocol GRE creates a virtual end-to-end network link between network nodes (that is routers), over a public network. GRE can be used to create simple VPN networks for customers that are connected to a service provider network, or between edge routers in a service provider environment, to exchange routing table updates. As this simple GRE interface does not support encryption, you may want to reconsider using GRE, if security is a priority. FreeBSD 7 natively supports creating and manipulating standard GRE tunnels. GRE support should be available in the FreeBSD's kernel. If you have not compiled GRE support into kernel, the GRE kernel module will be dynamically loaded into memory upon first usage. Creating gre(4) interface in a simple way usingifconfig(8) utility is shown here: # ifconfig gre0 create Note that if you do not specify the device node number, ifconfig takes the first available number and returns the new interface name, after creating the interface as follows: # ifconfig gre create gre1 You can also remove unnecessary gre(4) interface using ifconfig's destroy option: # ifconfig gre1 destroy Now that you have created a GRE interface, you should configure both sides of the GRE interface (on both hosts). This is basically done using the ifconfig utility. Consider the following scenario in the figure to establish a GRE tunnel between Host A and Host B:   To configure Host A, you should first create a gre0 interface and then specify both ends of the link on the interface.  
Read more
  • 0
  • 0
  • 2482

article-image-joomla-and-database
Packt
23 Oct 2009
8 min read
Save for later

Joomla! and Database

Packt
23 Oct 2009
8 min read
The Core Database Much of the data we see in Joomla! is stored in the database. A base installation has over thirty tables. Some of these are related to core extensions and others to the inner workings of Joomla!. There is an official database schema, which describes the tables created during the installation. For more information, please refer to: http://dev.joomla.org/ component/option,com_jd-wiki/Itemid,31/id,guidelines:database/. A tabular description is available at: http://dev.joomla.org/downloads/Joomla15_DB-Schema.htm. We access the Joomla! database using the global JDatabase object. The JDatabase class is an abstract class, which is extended by different database drivers. There are currently only two database drivers included in the Joomla! core, MySQL and MySQLi. We access the global JDatabase object using JFactory: $db =& JFactory::getDBO(); Extending the Database When we create extensions, we generally want to store data in some form. If we are using the database, it is important to extend it in the correct way. Table Prefix All database tables have a prefix, normally jos_, which helps in using a single database for multiple Joomla! installations. When we write SQL queries, to accommodate the variable table prefix, we use a symbolic prefix that is substituted with the actual prefix at run time. Normally the symbolic prefix is #__, but we can specify an alternative prefix if we want to. Schema Conventions When we create tables for our extensions, we must follow some standard conventions. The most important of these is the name of the table. All tables must use the table prefix and should start with name of the extension. If the table is storing a specific entity, add the plural of the entity name to the end of the table name separated by an underscore. For example, an items table for the extension 'My Extension' would be called #__myExtension_items. Table field names should all be lowercase and use underscore word separators; you should avoid using underscores if they are not necessary. For example, you can name an email address field as email. If you had a primary and a secondary email field, you could call them email and email_secondary; there is no reason to name the primary email address email_primary. If you are using a primary key record ID, you should call the field id, make it of type integer auto_increment, and disallow null. Doing this will allow you to use the Joomla! framework more effectively. Common Fields We may use some common fields in our tables. Using these fields will enable us to take advantage of the Joomla! framework. Publishing We use publishing to determine whether to display data. Joomla! uses a special field called published, of type tinyint(1); 0 = not published, 1 = published. Hits If we want to keep track of the number of times a record has been viewed, we canuse the special field hits, of type integer and with the default value 0. Checking Out To prevent more than one user trying to edit one record at a time we can check out records (a form of software record locking). We use two fields to do this, checked_out and checked_out_time. checked_out, of type integer, holds the ID of the user that has checked out the record. checked_out_time, of type datetime, holds the date and time when the record was checked out. A null date and a user ID of 0 is recorded if the record is not checked out. Ordering We often want to allow administrators the ability to choose the order in which items appear. The ordering field, of type integer, can be used to number records sequentially to determine the order in which they are displayed. This field does not need to be unique and can be used in conjunction with WHERE clauses to form ordering groups. Parameter Fields We use a parameter field, a TEXT field normally named params, to store additional information about records; this is often used to store data that determines how a record will be displayed. The data held in these fields is encoded as INI strings (which we handle using the JParameter class). Before using a parameter field, we should carefully consider the data we intend to store in the field. Data should only be stored in a parameter field if all of the following criteria are true: Not used for sorting records Not used in searches Only exists for some records Not part of a database relationship Schema Example Imagine we have an extension called 'My Extension' and an entity called foobar. The name of the table is #__myextension_foobars. This schema describes the table: Field Datatype NOT NULL AUTO INC UNSIGNED DEFAULT id INTEGER X X X NULL content TEXT X       checked_out INTEGER X   X 0 checked_out_time DATETIME X     0000-00-00 00:00:00 params TEXT X       ordering INTEGER X   X 0 hits INTEGER X   X 0 published TINYINT(1) X   X 0 This table uses all of the common fields and uses an auto-incrementing primary keyID field. When we come to define our own tables we must ensure that we use thecorrect data types and NOT NULL, AUTO INC, UNSIGNED and DEFAULT values. The SQL displayed below will create the table described in the above schema: CREATE TABLE `#__myextension_foobars` ( `id` INTEGER UNSIGNED NOT NULL DEFAULT NULL AUTO_INCREMENT, `content` TEXT NOT NULL DEFAULT '', `checked_out` INTEGER UNSIGNED NOT NULL DEFAULT 0, `checked_out_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', `params` TEXT NOT NULL DEFAULT '', `ordering` INTEGER UNSIGNED NOT NULL DEFAULT 0, `hits` INTEGER UNSIGNED NOT NULL DEFAULT 0, `published` INTEGER UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY(`id`)) CHARACTER SET `utf8` COLLATE `utf8_general_ci`; Date Fields We regularly use datetime fields to record the date and time at which an action has taken place. When we use these fields, it is important that we are aware of the effect of time zones. All dates and times should be recorded in UTC+0 (GMT / Z). When we come to display dates and times we can use the JDate class. The JDate class allows us to easily parse dates, output them in different formats, and apply UTC time-zone offsets. For more information about time zones, please refer to http://www.timeanddate.com. We often use parsers before we display data to make the data safe or to apply formatting to the data. We need to be careful how we store data that is going to be parsed. If the data is ever going to be edited, we must store the data in its RAW state. If the data is going to be edited extremely rarely and if the parsing is reversible, we may want to consider building a 'reverse-parser'. This way we can store the data in its parsed format, eradicating the need for parsing when we view the data and reducing the load on the server. Another option available tous is to store the data in both formats. This way we only have to parse data when we save it. Dealing with Multilingual Requirements Unlike ASCII and ANSII, Unicode is a multi-byte character set; it uses more than eight bits (one byte) per character. When we use UTF-8 encoding, character byte lengths vary. Unfortunately, MySQL versions prior to 4.1.2 assume that characters are always eight bits (one byte), which poses some problems. To combat the issue when installing extensions we have the ability to define different SQL files for servers, that do and do not support UTF-8. In MySQL servers that do not support UTF-8, when we create fields, which define a character length, we are actually defining the length in bytes. Therefore, if we try to store UTF-8 characters that are longer than one byte, we may exceed the size of the field. To combat this, we increase the length of fields to try to accommodate UTF-8strings. For example, a varchar(20) field becomes a varchar(60) field. We triple the size of fields because, although UTF-8 characters can be more than three bytes, the majority of common characters are a maximum of three bytes. This poses another issue, if we use a varchar(100) field, scaling it up for a MySQL server, which does not support UTF-8, we would have to define it as a varchar(300) field. We cannot do this because varchar fields have a maximum size of 255. The next step is slightly more drastic. We must redefine the field type so as it will accommodate at least three hundred bytes. Therefore, a varchar(100) field becomes a text field. As an example, the core #__content table includes a field named title. For MySQL severs that support UTF-8, the field is defined as: `title` varchar(255) NOT NULL default '' For MySQL severs that do not support UTF-8, the field is defined as: `title` text NOT NULL default '' We should also be aware that using a version of MySQL that does not support UTF-8 would affect the MySQL string handling functions. For example ordering by a string field may yield unexpected results. While we can overcome this using postprocessing in our scripts using the JString class, the recommended resolution is to upgrade to the latest version of MySQL.
Read more
  • 0
  • 0
  • 1787

article-image-chatroom-application-using-dwr-java-framework
Packt
23 Oct 2009
19 min read
Save for later

Chatroom Application using DWR Java Framework

Packt
23 Oct 2009
19 min read
Starting the Project and Configuration We start by creating a new project for our chat room, with the project name DWRChatRoom. We also need to add the dwr.jar file to the lib directory and enable DWR in the web.xml file. The following is the source code of the dwr.xml file. <?xml ver sion="1.0" encoding="UTF-8"?> <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr/dwr20.dtd"> <dwr> <allow> <create creator="new" javascript="Login"> <param name="class" value="chatroom.Login" /> </create> <create creator="new" javascript="ChatRoomDatabase"> <param name="class" value="chatroom.ChatRoomDatabase" /> </create> </allow> </dwr> The source code for web.xml is as follows: <?xml ver sion="1.0" encoding="UTF-8"?> <web-app xsi_schemaLocation="http://java. sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_ 5.xsd" id="WebApp_ID" version="2.5"> <display-name>DWRChatRoom</display-name> <servlet> <display-name>DWR Servlet</display-name> <servlet-name>dwr-invoker</servlet-name> <servlet-class> org.directwebremoting.servlet.DwrServlet </servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>activeReverseAjaxEnabled</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list></web-app> Developing the User Interface The next step we do is to create files for presentation: style sheet and HTML/JSP files. The style sheet, loginFailed.html, and index.jsp files are required for the application. The source code of the style sheet is as follows: body{margin:0;padding:0;line-height: 1.5em;}b{font-size: 110%;}em{color: red;}#topsection{background: #EAEAEA;height: 90px; /*Height of top section*/}#topsection h1{margin: 0;padding-top: 15px;}#contentwrapper{float: left;width: 100%;}#contentcolumn{margin-left: 200px; /*Set left margin to LeftColumnWidth*/}#leftcolumn{float: left;width: 200px; /*Width of left column*/margin-left: -100%;background: #C8FC98;}#footer{clear: left;width: 100%;background: black;color: #FFF;text-align: center;padding: 4px 0;}#footer a{color: #FFFF80;}.innertube{margin: 10px; /*Margins for inner DIV inside each column (to provide padding)*/margin-top: 0;} Our first page is the login page. It is located in the WebContent directory and it is named index.jsp. The source code for the page is given as follows: <%@ page language="java" contentType="text/html; charset=ISO-8859-1"    pageEncoding="ISO-8859-1"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Book Authoring</title><script type='text/javascript' src='/DWRChatroom/dwr/interface/Login.js'></script><script type='text/javascript' src='/DWRChatroom/dwr/engine.js'></script><script type='text/javascript' src='/DWRChatroom/dwr/util.js'></script>  <script type="text/javascript">function login(){  var userNameInput=dwr.util.byId('userName');  var userName=userNameInput.value;  Login.doLogin(userName,loginResult);}function loginResult(newPage){  window.location.href=newPage;}</script></head><body><h1>Book Authoring Sample</h1><table cellpadding="0" cellspacing="0"><tr><td>User name:</td><td><input id="userName" type="text" size="30"></td></tr><tr><td>&nbsp;</td><td><input type="button" value="Login" onclick="login();return false;"></td></tr></table></body></html> The login screen uses the DWR functionality to process the user login (the Java classes are presented after the web pages). The loginResults function opens either the failure page or the main page based on the result of the login operation. If the login was unsuccessful, a very simple loginFailed.html page is shown to the user, the source code for which is as follows: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html;                                         charset=ISO-8859-1"><title>Login failed</title></head><body><h2>Login failed.</h2></body></html> The main page, mainpage.jsp, includes all the client-side logic of our ChatRoom application. The source code for the page is as follows: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="en" xml_lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /><title>Chatroom</title><link href="styles.css" rel="stylesheet" type="text/css" /><%   if (session.getAttribute("username") == null         || session.getAttribute("username").equals("")) {      //if not logged in and trying to access this page      //do nothing, browser shows empty page      return;   }%><script type='text/javascript' src='/DWRChatRoom/dwr/interface/Login.js'></script><script type='text/javascript' src='/DWRChatRoom/dwr/interface/ChatRoomDatabase.js'></script><script type='text/javascript' src='/DWRChatRoom/dwr/engine.js'></script><script type='text/javascript' src='/DWRChatRoom/dwr/util.js'></script>  <script type="text/javascript">dwr.engine.setActiveReverseAjax(true);function logout(){  Login.doLogout(showLoginScreen);}function showLoginScreen(){  window.location.href='index.jsp';}function showUsersOnline(){  var cellFuncs = [          function(user) {             return '<i>'+user+'</i>';          }          ];    Login.getUsersOnline({    callback:function(users)     {      dwr.util.removeAllRows('usersOnline');      dwr.util.addRows( "usersOnline",users, cellFuncs,                                    { escapeHtml:false });    }    });}function getPreviousMessages(){    ChatRoomDatabase.getChatContent({    callback:function(messages)     {      var chatArea=dwr.util.byId('chatArea');      var html="";      for(index in messages)      {         var msg=messages[index];         html+=msg;      }      chatArea.innerHTML=html;      var chatAreaHeight = chatArea.scrollHeight;      chatArea.scrollTop = chatAreaHeight;    }    });}function newMessage(message){  var chatArea=dwr.util.byId('chatArea');  var oldMessages=chatArea.innerHTML;  chatArea.innerHTML=oldMessages+message;    var chatAreaHeight = chatArea.scrollHeight;  chatArea.scrollTop = chatAreaHeight;}function sendMessageIfEnter(event){  if(event.keyCode == 13)  {    sendMessage();  }}function sendMessage(){    var message=dwr.util.byId('messageText');    var messageText=message.value;    ChatRoomDatabase.postMessage(messageText);    message.value='';}</script></head><body onload="showUsersOnline();"><div id="maincontainer"><div id="topsection"><div class="innertube"><h1>Chatroom</h1><h4>Welcome <i><%=(String) session.getAttribute("username")%></i></h4></div></div><div id="contentwrapper"><div id="contentcolumn"><div id="chatArea" style="width: 600px; height: 300px; overflow: auto"></div><div id="inputArea"><h4>Send message</h4><input id="messageText" type="text" size="50"  onkeyup="sendMessageIfEnter(event);"><input type="button" value="Send msg"                                                      onclick="sendMessage();"></div></div></div><div id="leftcolumn"><div class="innertube"><table cellpadding="0" cellspacing="0">  <thead>    <tr>      <td><b>Users online</b></td>    </tr>  </thead>  <tbody id="usersOnline">  </tbody></table><input id="logoutButton" type="button" value="Logout"  onclick="logout();return false;"></div></div><div id="footer">Stylesheet by <a  href="http://www.dynamicdrive.com/style/">Dynamic Drive CSSLibrary</a></div></div><script type="text/javascript">getPreviousMessages();</script></body></html> The first chat-room-specific JavaScript function is getPreviousMessages(). This function is called at the end of mainpage.jsp, and it retrieves previous chat messages for this chat room. The newMessage() function is called by the server-side Java code when a new message is posted to the chat room. The function also scrolls the chat area automatically to show the latest message. The sendMessageIfEnter() and sendMessage() functions are used to send user messages to the server. There is the input field for the message text in the HTML code, and the sendMessageIfEnter() function listens to onkeyup events in the input field. If the user presses enter, the sendMessage() function is called to send the message to the server. The HTML code includes the chat area of specified size and with automatic scrolling. Developing the Java Code There are several Java classes in the application. The Login class handles the user login and logout and also keeps track of the logged-in users. The source code of the Login class is as follows: package chatroom;import java.util.Collection;import java.util.List;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.directwebremoting.ScriptSession;import org.directwebremoting.ServerContext;import org.directwebremoting.ServerContextFactory;import org.directwebremoting.WebContext;import org.directwebremoting.WebContextFactory;import org.directwebremoting.proxy.ScriptProxy;public class Login {   public Login() {   }      public String doLogin(String userName) {      UserDatabase userDb=UserDatabase.getInstance();      if(!userDb.isUserLogged(userName)) {         userDb.login(userName);         WebContext webContext= WebContextFactory.get();         HttpServletRequest request = webContext.getHttpServletRequest();         HttpSession session=request.getSession();         session.setAttribute("username", userName);         String scriptId = webContext.getScriptSession().getId();         session.setAttribute("scriptSessionId", scriptId);         updateUsersOnline();         return "mainpage.jsp";      }      else {         return "loginFailed.html";      }   }      public void doLogout() {      try {         WebContext ctx = WebContextFactory.get();         HttpServletRequest request = ctx.getHttpServletRequest();         HttpSession session = request.getSession();         Util util = new Util();         String userName = util.getCurrentUserName(session);         UserDatabase.getInstance().logout(userName);         session.removeAttribute("username");         session.removeAttribute("scriptSessionId");         session.invalidate();      } catch (Exception e) {         System.out.println(e.toString());      }      updateUsersOnline();   }      private void updateUsersOnline() {      WebContext webContext= WebContextFactory.get();      ServletContext servletContext = webContext.getServletContext();      ServerContext serverContext = ServerContextFactory.get(servletContext);      webContext.getScriptSessionsByPage("");      String contextPath = servletContext.getContextPath();      if (contextPath != null) {         Collection<ScriptSession> sessions =                            serverContext.getScriptSessionsByPage                                            (contextPath + "/mainpage.jsp");         ScriptProxy proxy = new ScriptProxy(sessions);         proxy.addFunctionCall("showUsersOnline");      }   }      public List<String> getUsersOnline() {      UserDatabase userDb=UserDatabase.getInstance();      return userDb.getLoggedInUsers();   }} The following is the source code of the UserDatabase class package chatroom;import java.util.List;import java.util.Vector;//this class holds currently logged in users//there is no persistencepublic class UserDatabase {      private static UserDatabase userDatabase=new UserDatabase();      private List<String> loggedInUsers=new Vector<String>();      private UserDatabase() {}      public static UserDatabase getInstance() {      return userDatabase;   }      public List<String> getLoggedInUsers() {      return loggedInUsers;   }      public boolean isUserLogged(String userName) {      return loggedInUsers.contains(userName);    }      public void login(String userName) {      loggedInUsers.add(userName);   }      public void logout(String userName) {      loggedInUsers.remove(userName);   }} The Util class is used by the Login class, and it provides helper methods for the sample application. The source code for the Util class is as follows: package chatroom;import java.util.Hashtable;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.directwebremoting.WebContext;import org.directwebremoting.WebContextFactory;public class Util {      public Util() {         }      public String getCurrentUserName() {      //get user name from session      WebContext ctx = WebContextFactory.get();      HttpServletRequest request = ctx.getHttpServletRequest();      HttpSession session=request.getSession();      return getCurrentUserName(session);   }   public String getCurrentUserName(HttpSession session) {      String userName=(String)session.getAttribute("username");      return userName;   }} The logic for the server-side chat room functionality is in the ChatRoomDatabase class. The source code for the ChatRoomDatabase is as follows: package chatroom;import java.util.Collection;import java.util.Date;import java.util.List;import java.util.Vector;import javax.servlet.ServletContext;import org.directwebremoting.ScriptSession;import org.directwebremoting.ServerContext;import org.directwebremoting.ServerContextFactory;import org.directwebremoting.WebContext;import org.directwebremoting.WebContextFactory;import org.directwebremoting.proxy.ScriptProxy;public class ChatRoomDatabase {   private static List<String> chatContent = new Vector<String>();   public ChatRoomDatabase() {   }   public void postMessage(String message) {      String user = (new Util()).getCurrentUserName();      if (user != null) {         Date time = new Date();         StringBuffer sb = new StringBuffer();         sb.append(time.toString());         sb.append(" <b><i>");         sb.append(user);         sb.append("</i></b>:  ");         sb.append(message);         sb.append("<br/>");         String newMessage=sb.toString();         chatContent.add(newMessage);         postNewMessage(newMessage);      }   }   public List<String> getChatContent() {      return chatContent;   }   private ScriptProxy getScriptProxyForSessions() {      WebContext webContext = WebContextFactory.get();      ServletContext servletContext = webContext.getServletContext();      ServerContext serverContext = ServerContextFactory.get(servletContext);      webContext.getScriptSessionsByPage("");      String contextPath = servletContext.getContextPath();      if (contextPath != null) {         Collection<ScriptSession> sessions = serverContext               .getScriptSessionsByPage(contextPath + "/mainpage.jsp");         ScriptProxy proxy = new ScriptProxy(sessions);         return proxy;      }      return null;   }   public void postNewMessage(String newMessage) {      ScriptProxy proxy = getScriptProxyForSessions();      if (proxy != null) {         proxy.addFunctionCall("newMessage",newMessage);      }   }} The Chatroom code is surprisingly simple. The chat content is stored in a Vector of Strings. The getChatContent()method just returns the chat content Vector to the browser. The postMessage()method is called when the user sends a new chat message. The method verifies whether the user is logged in, and adds the current time and username to the chat message and then appends the message to the chat content. The method also calls the postNewMessage() method that is used to show new chat content to all logged-in users. Note that the postMessage() method does not return any value. We let DWR and reverse AJAX functionality show the chat message to all users, including the user who sent the message. The getScriptProxyForSessions() and postNewMessage() methods use reverse AJAX to update the chat areas of all logged-in users with the new message. And that is it! The chat room sample is very straightforward and basic functionality is already in place, and the application is ready for further development. Testing the Chat We test the chat room application with three users: Smith, Brown, and Jones. We have given some screenshots of a typical scenario in a chat room here. Both Smith and Brown log into the system and exchange some messages. Both users see empty chat rooms when they log in and start chatting. The empty area that is above the send message input field is reserved for chat content. Smith and Brown exchange some messages as is seen in the following screenshot: The third user, Jones, joins the chat and sees all the previous messages in the chat room. Jones then exchanges some messages with Smith and Brown. Smith and Brown log out from the system leaving Jones alone in the chat room (until she also logs out). This is visible in the following screenshot: Summary This sample application showed how to use DWR in a chat room application. This application makes it clear that DWR makes development of these kind of collaborative applications very easy. DWR itself does not even play a big part in the applications. DWR is just a transparent feature of the application. So developers can concentrate on the actual project and aspects such as persistence of data and a neat user interface, instead of the low-level details of AJAX.    
Read more
  • 0
  • 0
  • 2726

article-image-ejb-3-security
Packt
23 Oct 2009
15 min read
Save for later

EJB 3 Security

Packt
23 Oct 2009
15 min read
Authentication and authorization in Java EE Container Security There are two aspects covered by Java EE container security: authentication and authorization. Authentication is the process of verifying that users are who they claim to be. Typically this is performed by the user providing credentials such as a password. Authorization, or access control, is the process of restricting operations to specific users or categories of users. The EJB specification provides two kinds of authorization: declarative and programmatic, as we shall see later in the article. The Java EE security model introduces a few concepts common to both authentication and authorization. A principal is an entity that we wish to authenticate. The format of a principal is application-specific but an example is a username. A role is a logical grouping of principals. For example, we can have administrator, manager, and employee roles. The scope over which a common security policy applies is known as a security domain, or realm. Authentication For authentication, every Java EE compliant application server provides the Java Authentication and Authorization Service (JAAS) API. JAAS supports any underlying security system. So we have a common API regardless of whether authentication is username/password verification against a database, iris or fingerprint recognition for example. The JAAS API is fairly low level and most application servers provide authentication mechanisms at a higher level of abstraction. These authentication mechanisms are application-server specific however. We will not cover JAAS any further here, but look at authentication as provided by the GlassFish application server. GlassFish Authentication There are three actors we need to define on the GlassFish application server for authentication purposes: users, groups, and realms. A user is an entity that we wish to authenticate. A user is synonymous with a principal. A group is a logical grouping of users and is not the same as a role. A group's scope is global to the application server. A role is a logical grouping of users whose scope is limited to a specific application. Of course for some applications we may decide that roles are identical to groups. For other applications we need some mechanism for mapping the roles onto groups. We shall see how this is done later. A realm, as we have seen, is the scope over which a common security policy applies. GlassFish provides three kinds of realms: file, certificate, and admin-realm. The file realm stores user, group, and realm credentials in a file named keyfile. This file is stored within the application server file system. A file realm is used by web clients using http or EJB application clients. The certificate realm stores a digital certificate and is used for authenticating web clients using https. The admin-realm is similar to the file realm and is used for storing administrator credentials. GlassFish comes pre-configured with a default file realm named file. We can add, edit, and delete users, groups, and realms using the GlassFish administrator console. We can also use the create-file-user option of the asadmin command line utility. To add a user named scott to a group named bankemployee, in the file realm, we would use the command: <target name="create-file-user"> <exec executable="${glassfish.home}/bin/asadmin" failonerror="true" vmlauncher="false"> <arg line="create-file-user --user admin --passwordfile userpassword --groups bankemployee scott"/> </exec> </target> --user specifies the GlassFish administrator username, admin in our example. --passwordfile specifies the name of the file containing password entries. In our example this file is userpassword. Users, other than GlassFish administrators, are identified by AS_ADMIN_USERPASSWORD. In our example the content of the userpassword file is: AS_ADMIN_USERPASSWORD=xyz This indicates that the user's password is xyz. --groups specifies the groups associated with this user (there may be more than one group). In our example there is just one group, named bankemployee. Multiple groups are colon delineated. For example if the user belongs to both the bankemployee and bankcustomer groups, we would specify: --groups bankemployee:bankcustomer The final entry is the operand which specifies the name of the user to be created. In our example this is scott. There is a corresponding asadmin delete-file-user option to remove a user from the file realm. Mapping Roles to Groups The Java EE specification specifies that there must be a mechanism for mapping local application specific roles to global roles on the application server. Local roles are used by an EJB for authorization purposes. The actual mapping mechanism is application server specific. As we have seen in the case of GlassFish, the global application server roles are called groups. In GlassFish, local roles are referred to simply as roles. Suppose we want to map an employee role to the bankemployee group. We would need to create a GlassFish specific deployment descriptor, sun-ejb-jar.xml, with the following element: <security-role-mapping> <role-name>employee</role-name> <group-name>bankemployee</group-name> </security-role-mapping> We also need to access the configuration-security screen in the administrator console. We then disable the Default Principal To Role Mapping flag. If the flag is enabled then the default is to map a group onto a role with the same name. So the bankemployee group will be mapped to the bankemployee role. We can leave the default values for the other properties on the configuration-security screen. Many of these features are for advanced use where third party security products can be plugged in or security properties customized. Consequently we will give only a brief description of these properties here. Security Manager: This refers to the JVM security manager which performs code-based security checks. If the security manager is disabled GlassFish will have better performance. However, even if the security manager is disabled, GlassFish still enforces standard Java EE authentication/authorization. Audit Logging: If this is enabled, GlassFish will provide an audit trail of all authentication and authorization decisions through audit modules. Audit modules provide information on incoming requests, outgoing responses and whether authorization was granted or denied. Audit logging applies for web-tier and ejb-tier authentication and authorization. A default audit module is provided but custom audit modules can also be created. Default Realm: This is the default realm used for authentication. Applications use this realm unless they specify a different realm in their deployment descriptor. The default value is file. Other possible values are admin-realm and certificate. We discussed GlassFish realms in the previous section. Default Principal: This is the user name used by GlassFish at run time if no principal is provided. Normally this is not required so the property can be left blank. Default Principal Password: This is the password of the default principal. JACC: This is the class name of a JACC (Java Authorization Contract for Containers) provider. This enables the GlassFish administrator to set up third-party plug in modules conforming to the JACC standard to perform authorization. Audit Modules: If we have created custom modules to perform audit logging, we would select from this list. Mapped Principal Class: This is only applicable when Default Principal to Role Mapping is enabled. The mapped principal class is used to customize the java.security.Principal implementation class used in the default principal to role mapping. If no value is entered, the com.sun.enterprise.deployment.Group implementation of java.security.Principal is used. Authenticating an EJB Application Client Suppose we want to invoke an EJB, BankServiceBean, from an application client. We also want the application client container to authenticate the client. There are a number of steps we first need to take which are application server specific. We will assume that all roles will have the same name as the corresponding application server groups. In the case of GlassFish we need to use the administrator console and enable Default Principal To Role Mapping. Next we need to define a group named bankemployee with one or more associated users. An EJB application client needs to use IOR (Interoperable Object Reference) authentication. The IOR protocol was originally created for CORBA (Common Object Request Broker Architecture) but all Java EE compliant containers support IOR. An EJB deployed on one Java EE compliant vendor may be invoked by a client deployed on another Java EE compliant vendor. Security interoperability between these vendors is achieved using the IOR protocol. In our case the client and target EJB both happen to be deployed on the same vendor, but we still use IOR for propagating security details from the application client container to the EJB container. IORs are configured in vendor specific XML files rather than the standard ejb-jar.xml file. In the case of GlassFish, this is done within the <ior-security-config> element within the sun-ejb-jar.xml deployment descriptor file. We also need to specify the invoked EJB, BankServiceBean, in the deployment descriptor. An example of the sun-ejb-jar.xml deployment descriptor is shown below: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD       Application Server 9.0 EJB 3.0//EN"       "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd"> <sun-ejb-jar>   <enterprise-beans>     <ejb>       <ejb-name>BankServiceBean</ejb-name>         <ior-security-config>           <as-context>              <auth-method>USERNAME_PASSWORD</auth-method>              <realm>default</realm>              <required>true</required>           </as-context>         </ior-security-config>     </ejb>   </enterprise-beans> </sun-ejb-jar> The as in <as-context> stands for the IOR authentication service. This specifies authentication mechanism details. The <auth-method> element specifies the authentication method. This is set to USERNAME_PASSWORD which is the only value for an application client. The <realm> element specifies the realm in which the client is authenticated. The <required> element specifies whether the above authentication method is required to be used for client authentication. When creating the corresponding EJB JAR file, the sun-ejb-jar.xml file should be included in the META-INF directory, as follows: <target name="package-ejb" depends="compile">     <jar jarfile="${build.dir}/BankService.jar">         <fileset dir="${build.dir}">              <include name="ejb30/session/**" />                           <include name="ejb30/entity/**" />               </fileset>               <metainf dir="${config.dir}">             <include name="persistence.xml" />                          <include name="sun-ejb-jar.xml" />         </metainf>     </jar> </target> As soon as we run the application client, GlassFish will prompt with a username and password form, as follows: If we reply with the username scott and password xyz the program will run. If we run the application with an invalid username or password we will get the following error message: javax.ejb.EJBException: nested exception is: java.rmi.AccessException: CORBA NO_PERMISSION 9998 ..... EJB Authorization Authorization, or access control, is the process of restricting operations to specific roles. In contrast with authentication, EJB authorization is completely application server independent. The EJB specification provides two kinds of authorization: declarative and programmatic. With declarative authorization all security checks are performed by the container. An EJB's security requirements are declared using annotations or deployment descriptors. With programmatic authorization security checks are hard-coded in the EJBs code using API calls. However, even with programmatic authorization the container is still responsible for authentication and for assigning roles to principals. Declarative Authorization As an example, consider the BankServiceBean stateless session bean with methods findCustomer(), addCustomer() and updateCustomer(): package ejb30.session; import javax.ejb.Stateless; import javax.persistence.EntityManager; import ejb30.entity.Customer; import javax.persistence.PersistenceContext; import javax.annotation.security.RolesAllowed; import javax.annotation.security.PermitAll; import java.util.*; @Stateless @RolesAllowed("bankemployee") public class BankServiceBean implements BankService { @PersistenceContext(unitName="BankService") private EntityManager em; private Customer cust; @PermitAll public Customer findCustomer(int custId) { return ((Customer) em.find(Customer.class, custId)); } public void addCustomer(int custId, String firstName, String lastName) { cust = new Customer(); cust.setId(custId); cust.setFirstName(firstName); cust.setLastName(lastName); em.persist(cust); } public void updateCustomer(Customer cust) { Customer mergedCust = em.merge(cust); } } We have prefixed the bean class with the annotation: @RolesAllowed("bankemployee") This specifies the roles allowed to access any of the bean's method. So only users belonging to the bankemployee role may access the addCustomer() and updateCustomer() methods. More than one role can be specified by means of a brace delineated list, as follows: @RolesAllowed({"bankemployee", "bankcustomer"}) We can also prefix a method with @RolesAllowed, in which case the method annotation will override the class annotation. The @PermitAll annotation allows unrestricted access to a method, overriding any class level @RolesAllowed annotation. As with EJB 3 in general, we can use deployment descriptors as alternatives to the @RolesAllowed and @PermitAll annotations. Denying Authorization Suppose we want to deny all users access to the BankServiceBean.updateCustomer() method. We can do this using the @DenyAll annotation: @DenyAll public void updateCustomer(Customer cust) { Customer mergedCust = em.merge(cust); } Of course if you have access to source code you could simply delete the method in question rather than using @DenyAll. However suppose you do not have access to the source code and have received the EJB from a third party. If you in turn do not want your clients accessing a given method then you would need to use the <exclude-list> element in the ejb-jar.xml deployment descriptor: <?xml version="1.0" encoding="UTF-8"?> <ejb-jar version="3.0"                         xsi_schemaLocation="http://java.sun.com/xml/ns/javaee             http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"> <enterprise-beans> <session> <ejb-name>BankServiceBean</ejb-name> </session> </enterprise-beans> <assembly-descriptor> <exclude-list><method> <ejb-name>BankServiceBean</ejb-name> <method-name>updateCustomer</method-name></method></exclude-list> </assembly-descriptor> </ejb-jar> EJB Security Propagation Suppose a client with an associated role invokes, for example, EJB A. If EJB A then invokes, for example, EJB B then by default the client's role is propagated to EJB B. However, you can specify with the @RunAs annotation that all methods of an EJB execute under a specific role. For example, suppose the addCustomer() method in the BankServiceBean EJB invokes the addAuditMessage() method of the AuditServiceBean EJB: @Stateless @RolesAllowed("bankemployee") public class BankServiceBean implements BankService { private @EJB AuditService audit; ....      public void addCustomer(int custId, String firstName,                                                          String lastName) {              cust = new Customer();              cust.setId(custId);              cust.setFirstName(firstName);              cust.setLastName(lastName);              em.persist(cust);              audit.addAuditMessage(1, "customer add attempt");      }      ... } Note that only a client with an associated role of bankemployee can invoke addCustomer(). If we prefix the AuditServiceBean class declaration with @RunAs("bankauditor") then the container will run any method in AuditServiceBean as the bankauditor role, regardless of the role which invokes the method. Note that the @RunAs annotation is applied only at the class level, @RunAs cannot be applied at the method level. @Stateless @RunAs("bankauditor") public class AuditServiceBean implements AuditService { @PersistenceContext(unitName="BankService") private EntityManager em; @TransactionAttribute( TransactionAttributeType.REQUIRES_NEW) public void addAuditMessage (int auditId, String message) { Audit audit = new Audit(); audit.setId(auditId); audit.setMessage(message); em.persist(audit); } } Programmatic Authorization With programmatic authorization the bean rather than the container controls authorization. The javax.ejb.SessionContext object provides two methods which support programmatic authorization: getCallerPrincipal() and isCallerInRole(). The getCallerPrincipal() method returns a java.security.Principal object. This object represents the caller, or principal, invoking the EJB. We can then use the Principal.getName() method to obtain the name of the principal. We have done this in the addAccount() method of the BankServiceBean as follows: Principal cp = ctx.getCallerPrincipal(); System.out.println("getname:" + cp.getName()); The isCallerInRole() method checks whether the principal belongs to a given role. For example, the code fragment below checks if the principal belongs to the bankcustomer role. If the principal does not belong to the bankcustomer role, we only persist the account if the balance is less than 99. if (ctx.isCallerInRole("bankcustomer")) {     em.persist(ac); } else if (balance < 99) {            em.persist(ac);   } When using the isCallerInRole() method, we need to declare all the security role names used in the EJB code using the class level @DeclareRoles annotation: @DeclareRoles({"bankemployee", "bankcustomer"}) The code below shows the BankServiceBean EJB with all the programmatic authorization code described in this section: package ejb30.session; import javax.ejb.Stateless; import javax.persistence.EntityManager; import ejb30.entity.Account; import javax.persistence.PersistenceContext; import javax.annotation.security.RolesAllowed; import java.security.Principal; import javax.annotation.Resource; import javax.ejb.SessionContext; import javax.annotation.security.DeclareRoles; import java.util.*; @Stateless @DeclareRoles({"bankemployee", "bankcustomer"}) public class BankServiceBean implements BankService { @PersistenceContext(unitName="BankService") private EntityManager em; private Account ac; @Resource SessionContext ctx; @RolesAllowed({"bankemployee", "bankcustomer"}) public void addAccount(int accountId, double balance, String accountType) { ac = new Account(); ac.setId(accountId); ac.setBalance(balance); ac.setAccountType(accountType); Principal cp = ctx.getCallerPrincipal(); System.out.println("getname:" + cp.getName()); if (ctx.isCallerInRole("bankcustomer")) { em.persist(ac); } else if (balance < 99) { em.persist(ac); } } ..... } Where we have a choice declarative authorization is preferable to programmatic authorization. Declarative authorization avoids having to mix business code with security management code. We can change a bean's security policy by simply changing an annotation or deployment descriptor instead of modifying the logic of a business method. However, some security rules, such as the example above of only persisting an account within a balance limit, can only be handled by programmatic authorization. Declarative security is based only on the principal and the method being invoked, whereas programmatic security can take state into consideration. Because an EJB is typically invoked from the web-tier by a servlet, JSP page or JSF component, we will briefly mention Java EE web container security. The web-tier and EJB tier share the same security model. So the web-tier security model is based on the same concepts of principals, roles and realms.
Read more
  • 0
  • 0
  • 4478

article-image-oracle-web-services-manager-authentication-and-authorization
Packt
23 Oct 2009
6 min read
Save for later

Oracle Web Services Manager: Authentication and Authorization

Packt
23 Oct 2009
6 min read
Here, we will see: Steps involved in the authentication and authorization process Learning file authentication and authorization Implementing active directory authentication and authorization Details of policy template Steps Involved in the Authentication and Authorization Process Oracle Web Services Manager can authenticate the web services request by validating the credentials against a data store. The credentials (e.g. username and password, SAML token, certificate, etc.) that are attached to the web services will be validated against the data store, such as the file system, databases, active directory and any LDAP compliant directory. Once authentication is successful, the next step is to perform authorization by validating the username against a set of pre-defined groups which have access to the web service. The following figure shows the process where the user accesses an application which acts as a client for the web service. The client application then attaches the username and password to make the web service request. The username and password are then validated against file system or LDAP directory by Oracle WSM, either using the gateway or the agent. The authentication and authorization against different directory stores can be configured using Oracle WSM policy steps. Oracle Web Services Manager has predefined policy steps for: File Authenticate and Authorize Active Directory Authenticate and Authorize LDAP Authenticate and Authorize In the previous figure, the Oracle WSM Gateway is used to protect the web services and externalize the security. In order to authenticate and authorize requests to web services, the web services can be registered within the gateway and the request pipeline of gateway will validate the credentials and authorize the access before it forwards the request to the actual web service provider. The gateway steps for authentication and authorization can be summarized as: Log incoming request (optional) Extract credentials get the credentials from the SOAP message or HTTP header) Authenticate (file authenticate, active directory authenticate, etc.) Authorize (file authorize, active directory authorize, etc.) Request is forwarded to the web service provider The response from the web service also follows through a similar response pipeline where you can implement the log, encryption of response, or signing, or response, etc. While it is not required to implement any steps in the response pipeline, there should be a response pipeline even if it's doing nothing. Oracle WSM: File Authenticate and Authorize Oracle Web Services MManager can authenticate the web services requests against a file that has the list of usernames and passwords. In this example, the username and password information are part of the SOAP message, however one can also send a username and password as HTTP header, or it can be any XMML data that is a part of the web services message. While file-based authentication can easily be compromised, it is often used as a jump start or testing process to validate the authentication and authorization process. Authentication and authorization of web service requests against a file requires three main steps, and these are described below. There is a default log step which will log all the request and response messages, and you can also include that log step at any point to log messages: Extract Credentials File Authenticate File Authorize The first step to authenticate a web service request against a password file (file authenticate) is to extract the username and password credentials from the SOAP message. The client application attaches the username and password to the SOAP message, as per the UserName token profile. In the policy to authenticate the web service against the file, add the step in the request process to extract credentials. Since this is a web service request, as opposed to HTTP post, configure the Credentials location to WS-BASIC (refer to the following screenshot). Note: WS-BASIC means that it is WS-security compliant. WS-security is the oasis specification that specifies how security tokens are inserted as a part of the SOAP message. In other words, WS-BASIC means that the username and password can be found in the SOAP message, as per the username token profile of the WS-security specification. Once the credentials are extracted, the next step is to validate them against the file. The default implementation of the Oracle WSM File Authenticate requires the username and password to be in a comma separated format and the password should be the hash value using a MMD5 or SHA1 algorithm. In order to authenticate the credentials against the data store, the next step is to configure the File Authenticate step in Oracle WSMM. In this step, the options are straightforward. We have to configure the location of the password file and the hash algorithm format as either md5 or SHA1 (see the next screenshot). The sample file with username and password is: bob:{MD5}jK2x5HPF1b3NIjcmjdlDNA== You can use the wsmadmin tool provided as part of Oracle WSMM standalone or SOA suite). Type: wsmadmin md5encode bob password c;.htpasswd     Now that the authentication steps are configured, the next step is to configure the authorization policy step to ensure that only valid users can access the web service. For the file authorization method, it is no different than the file authenticate method i.e. even the user-to-role mappings are kept in the file. The following figure shows the File Authorize policy step. In this step, we have to define the location of the XML file that contains the users to roles mapping, and also the list of roles that should be allowed to access the service. The roles XML file should look like: <?xml version=‘1.0' encoding=‘utf-8'?> <UserRoles> <user username="joe" roles="guest"/> <user username="Bob" roles="Admin,guest"/> </UserRoles> In the previous XML file, the list of roles the user belongs to are defined as a value of roles element and is comma separated. Now that we have completed the steps to extract credentials, authenticate the request and also authorize the request, the next step is to save the policy steps and commit the policy changes. Once the policy is committed, any request to that web service would require a username and password, and that user should have necessary privileges to access the service. Oracle WSM: Active Directory Authenticate and Authorize In the previous section, we discussed authenticating and authorizing web service requests against a file. Though it's an easy start, security based on a file system can be easily compromised and will be tough to maintain. Authentication and authorization of web services are better handled when integrated with a native LDAP directory, such as active directory, so that the AD administrator can manage users and group membership. In this section, we will discuss how to authenticate and authorize web service requests against an active directory. Active-directory-based authentication and authorization of web service requests involves the same steps as file-based-authentication and authorization, and they are: Extract Credentials Active Directory Authenticate Active Directory Authorize
Read more
  • 0
  • 0
  • 20706

article-image-expressionengine-creating-photo-gallery
Packt
23 Oct 2009
6 min read
Save for later

ExpressionEngine: Creating a Photo Gallery

Packt
23 Oct 2009
6 min read
Install the Photo Gallery Module The photo gallery in ExpressionEngine is considered a separate module, even though it is included with every personal or commercial ExpressionEngine license. Installing it is therefore very simple: Log into the control panel using http://localhost/admin.php or http://www.example.com/admin.php, and select Modules from the top of the screen. About a quarter of the way down the page, we can see the Photo Gallery module. In the far-right column is a link to install it. Click Install. We will see a message at the top of the screen indicating that the photo gallery module was installed. That's it! Setting Up Our Photo Gallery Now that we have installed the photo gallery module, we need to define some basic settings and then create categories that we can use to organize our photos. Define the Basic Settings Still in the Modules tab, the photo gallery module should now have become a clickable link. Click on the Photo Gallery. We are presented with a message that says There are no image galleries. Select to Create a New Gallery. We are now prompted for our Image Folder Name. For our photo galleries, we are going to create a folder for our photos inside the images folder that should already exist. Navigate to C:xampphtdocsimages (or /Applications/MAMP/htdocs/images if using MAMP on a Mac) or to the images folder on your web server, and create a new folder called photos. Inside that folder, we are going to create a specific subfolder for our toast gallery images. (This will keep our article photos separate from any other galleries we may wish to create). Call the new folder toast. If doing this on a web server, set the permissions of the toast folder to 777 (read, write, and execute for owner, group, and public). This will allow everyone to upload images to this folder. Back in ExpressionEngine, type in the name of the folder we just created (toast) and hit Submit. We are now prompted to name our template gallery. We will use the imaginative name of toastgallery so that it is distinguishable from any other galleries we may create in the future. This name is what will be used as the default URL to the gallery and will be used as the template group name for our gallery templates. Hit Submit. We are now prompted to update the preferences for our new gallery. Expand the General Configuration option and define a Photo Gallery Name and Short Name. We are going to use Toast Photos as a Photo Gallery Name and toastphotos as a Short Name. The short name is what will be used in our templates to reference this photo gallery Next, expand the Image Paths section. Here the Image Folder Name should be the same name as the folder we created earlier (in our case toast). For XAMPP users, the Server Path to Image Directory is going to be C:/xampp/htdocs/images/photos/toast, and the Full URL to Image Directory is going to be http://localhost/images/photos/toast. For MAMP users on a Mac or when using a web server, these paths are going to be different depending on your setup. Verify these settings for correctness, making adjustments as necessary. Whenever we upload an image into the image gallery, ExpressionEngine creates three copies of the image—a medium-sized and a thumbnail-sized version of the image, in addition to the original image. The thumbnail image is fairly small, so we are going to double the size of the thumbnail image. Expand the Thumbnail Resizing Preferences section, and instead of a Thumbnail Width of 100, choose a width of 200. Check the box (the one outside of the text box) and the height should update to 150. Hit Submit to save the settings so far. We will review the rest of the settings later. We have now created our first gallery. However, before we can start uploading photos, we need to create some categories. Create Categories For the purposes of our toast website, we are going to create categories based on the seasons: spring, summer, autumn, and winter. We are going to have separate subfolders for each of the categories; these are created automatically when we create the categories. To do this, first select Categories from the new menu that has appeared across the top of the screen. We will see a message that says No categories exist. Select Add a New Category. We are going to use a Category Name of Spring and a Description that describes the category—we will later display this description on our site. We are going to create a Category Folder of spring. Leave the Category Parent as None, and hit Submit. Select Add a New Category, and continue to add three more categories: summer, autumn, and winter in the same way. After we a re done with creating all the categories, use the up and down arrows to order the categories correctly. In our case, we need to move Autumn down so that it appears after Summer. We now have the beginnings of a photo gallery. Next, we will upload our first photos so that we can see how the gallery works. Upload Our First Photos To upload a photo to a photo gallery is pretty straightforward. The example photos we are working with can be downloaded from the Packtpub support page at http://www.packtpub.com/files/code/3797_Graphics.zip. To upload a photo, select New Entry from the menu within the photo gallery module. For the File Name, click the Browse...> button and browse to the photo spring1.jpg. We are going to give this an Entry Title of Spring Flower. For Date, we could either leave it as a default or enter the date that the photo was taken on. We are going to use a date of 2006-04-22. Click on the calendar icon to expand the view to include a calendar that can be easily navigated. We are going to use a Category of Spring and a Status of Open. Leave the box checked to Allow Comments, and write a Caption that describes the photo. The Views allows us to indicate how many times this image has been viewed—in this case we are going to leave it at 0. Hit Submit New Entry when everything is done. We are presented with a message that reads Your file has been successfully submitted, and the image now appears underneath the entry information. In the folder where our image is uploaded, three versions of the same image are made. There is the original file (spring1.jpg), a thumbnail of the original file (spring1_thumb.jpg), and a medium-sized version of the original file (spring1_medium.jpg). Now, click on New Entry and repeat the same steps to upload the rest of the photos, using appropriate categories and descriptions that describe the photos. There are four example photos for each season (for example, winter1.jpg, winter2.jpg, winter3.jpg, and winter4.jpg). Having a few example photos in each category will better demonstrate how the photo gallery works.
Read more
  • 0
  • 0
  • 3602
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-working-sbs-services-user-part-1
Packt
23 Oct 2009
6 min read
Save for later

Working with SBS Services as a User: Part 1

Packt
23 Oct 2009
6 min read
E-mail, Calendar, and Contacts SBS 2008 includes Exchange 2007, which provides E-mail, Calendar, and Contact functionality. This is available through Outlook, over the Web via Outlook Web Access and on mobile devices. If the user makes a change to one, it will be replicated to Exchange and then to the other locations. How to access from the other locations will be covered later in this article. I'm going to presume that you understand how to send and read email and create and use contacts, but I will share some useful scenarios that many small businesses benefit from, but don't always understand are present in SBS 2008. Some of these will rely on Office 2007 with Outlook, while others can be seen via the web-based interface too. The scenarios are: Viewing your calendar and other people's calendars Scheduling a meeting for multiple people and ensuring their diaries are all free for the time period Telling people when you are going to be away or unavailable Finding emails that have been filed Recovering emails that have been deleted and removed from the deleted items folder All of the actions in this section are carried out on a user's computer, logged in as that user. Only where SBS 2008 is explicitly mentioned, is there an action that is carried out on the server. Outlook 2003 and 2007 connection configuration To configure Microsoft Outlook 2007, you should simply have to open Outlook as it should auto-configure itself. Outlook 2003 will require configuring, but I'm only going cover the important sections here. For full instructions, click on the link How do I use Outlook Anywhere, on the Remote Web Workplace main screen. The links on Remote Web Workplace point to addresses that begin with https://sites/..., which is not accessible from outside the SBS 2008 network. This should be changed to https://remote.yourdomain.co.uk/... as described later in this article. If this has not been done and a user needs access to the information, then they can edit the address in their browser replacing the first part of the URL as described above. If you need to manually configure Outlook, you will need to select the server as an Exchange server. The name of the Microsoft Exchange Server is the name of your SBS 2008 server. In the following screenshot, the name of my SBS 2008 server is davidoverserver and this is entered into the Microsoft Exchange Server section, along with the User Name of the user I am logged in as on their computer. You can either click on Next to finish the settings, or if this is a laptop or a machine that may access SBS 2008 from a remote location, click on More Settings. Click on the Connection tab and then put a check mark in the Connect to my Exchange mailbox using HTTP check box. Finally, click the button Exchange Proxy Settings. Once the proxy settings are open, you will need to type in the remote access URL for your server and also check the Mutually authenticate the session when connecting with SSL, and then enter the name of your remote access server, preceded by msstd:. Clicking on OK will enable you to finish the configuration. Once these changes have been enabled, Outlook will connect to the network without any further action—provided you have an Internet connection, and should work offline until it gets an Internet connection. Calendar management SBS 2008 provides each user a calendar that they can use to manage their diary and which they can choose to share with colleagues if they desire. The level of details shared can be from very basic free and busy time slots through to enabling someone else to have the ability to see and change the diary. This availability of information does concern some users, which is why they can also mark any appointment as private and no details will be shared with others, even if the calendar has been fully shared. Outlook on the desktop enables access to both your and other's calendars, while Outlook and Windows Mobile devices offer much less, if any, access to other people's calendars. I will only describe each task from Outlook in this section, and will provide more information on using Outlook Web Access later in this article. Viewing Calendars Start Outlook from the Start menu. Once Outlook has loaded, click on the Calendar button or go to the Go menu and select Calendar from the menu. You will see your calendar displayed, normally in the Day format with today showing. In the example below, you can see the padlock for the private appointment that others can't see, two normal appointments, and the tentative appointment that is not confirmed at 17:00. To open another person's calendar, click the Open a Shared Calendar link on the lefthand side and then type in the name of the person whose calendar you want to see. If you have permission to view their calendar, you will see both calendars side by side as follows: If you do not have permission and you are running Outlook 2007, you will be prompted to send an email requesting permission. The email will look like this: If the person receiving this email has Outlook 2007, they simply click on Accept to enable you to view the calendar. If you or they have an earlier version of Outlook, then the person whose calendar you want to view will need to carry this task out by hand. To do this, get that individual to open Outlook and then their Calendar and right-click on Calendar under My Calendars and then select Properties from the menu. When the properties appear, go to the Permissions tab and either add the user and assign specific permission, or to make life easier, simply set the default access to reviewer. You can now view both your and other's calendars to identify opportunities to meet. You can open more than one other person's calendar, but things can get confusing with so many open. With Office 2007, you can overlay the calendars by clicking the arrow next to someone's name. For all versions of Outlook, you close a calendar by removing the check mark next to their name in the lefthand navigation pane.
Read more
  • 0
  • 0
  • 3045

article-image-user-management-zenoss
Packt
23 Oct 2009
2 min read
Save for later

User Management in Zenoss

Packt
23 Oct 2009
2 min read
User Accounts and their Properties Working as the non-admin user has several benefits: Changes to settings are tracked via user name Custom alerting rules can be defined per user Access can be restricted per user Let's add a new user: Select Settings from the navigation panel. Select the Users tab. From the Users table menu, select Add New User. Enter the User Name and Email address in the Add User dialog box. Click OK to create the user account. The new user name is added to the list of users (see following screenshot) along with columns for Email address, Pager, address, and Roles. Before a new user can log in, we must specify a password. To create a password and configure the account, edit the user account by clicking on the user name from the Users table. The following table includes the fields we can set via the Edit Screen.   Property Description Password Specify the new password in the first text field. Retype the password in the second box and click save to verify the passwords match. Roles Specify a user role. Available options are Manager, ZenManager, and ZenUser. Groups If the user is a member of a defined group, select it. Groups are defined in Settings > Users. Email Enter an email address if the user has to receive alerts via email. Pager Enter a pager number if the user will receive alerts via pager. Default Page Size Specify number of entries displayed in a grid listing. Default is 40. Default Admin Role Select the default role for administered objects. Default Admin Level This field is not currently used and is reserved for future use. Dashboard Refresh Enter the time in seconds that the dashboard refreshes for the user. The default is 30 seconds. Dashboard Timeout Enter the time in seconds before the dashboard refresh timeouts. The default is 25 seconds. Dashboard Organizer Select the organizer view for the Device Issues dashboard portlet. The user can change or select a new organizer via the Preferences link. Available options include: Devices Systems Groups Locations Network Map Start Object Specify a default network from the monitored networks to map on the Network Maps view. For example, 192.168.1.1.
Read more
  • 0
  • 0
  • 3764

article-image-customizing-default-theme-drupal
Packt
23 Oct 2009
3 min read
Save for later

Customizing the Default Theme in Drupal

Packt
23 Oct 2009
3 min read
Let's look at the default theme (garland) and customize it. We can customize the following features: Color scheme, either based on a color set, or by changing the individual colors If certain elements, such as the logo, are displayed The logo The favicon Back in the Themes section of the Administer area, there is a configure link next to each theme; if we click this we are taken to the theme's configuration page. Although Doug ideally wants a new theme that is unique to his website, he also wants to have a look at a few different options for the default theme. In particular, he wants to add his company's logo to the website and try a number of red color schemes as those are his corporate colors. Color Scheme The color scheme settings are quite intuitive and easy to change. We can either: Select a color set Change each color by entering the hexadecimal color codes (the # followed by 6 characters) Select the colors from the color wheel To change a color using the color wheel, we need to click on the color type (base color, link color, etc.) to select it and then chose the general color from the wheel and the shade of the color from the square within. When we change the colors or color set, the preview window below the settings automatically updates to reflect the color change. The following color sets are available: Blue Lagoon (the default set) Ash Aquamarine Belgian Chocolate Bluemarine Citrus Blast Cold Day Greenbeam Meditarrano Mercury Nocturnal Olivia Pink Plastic Shiny Tomato Teal Top Custom Quite a number of these are red-based color schemes, let's look into them, they are: Belgian Chocolate Meditarrano Shiny Tomato Belgian Chocolate Color Set The Belgian Chocolate color set uses a dark red header with a gradient starting with black flowing into a dark red color. The page's background is a cream color and the main content area has a white background as illustrated by the picture below: Mediterrano Color Set The Mediterrano color set uses a lighter red color where the gradient in the header starts with a light orange color which then flows into a light red color. Similar to the Belgian Chocolate color scheme the background is cream in color with a white background for the content area. Shiny Tomato Color Set The Shiny Tomato color set has a gradient header that starts with deep red and flows into a bright red color. The page's background is light grey with white background for the main content area, reflecting a professional image. The Shiny Tomato color set uses a red scheme which is in Doug's logo and he feels this set is the most professional of the three and wants us to use that.  
Read more
  • 0
  • 0
  • 1733

article-image-planning-extensions-typo3
Packt
23 Oct 2009
8 min read
Save for later

Planning Extensions in TYPO3

Packt
23 Oct 2009
8 min read
Why is Planning Important? Most open source developers see planning as a boring task. Why plan if one can just go and code? The answer is as simple as the question: The "Go and code" approach does not let us create truly optimal code. Portions of code have to be changed while other portions are written. They often lead to redundant code or uninitialized variables, partially covered conditions, and wrong return results. Code gets a "do not touch" reputation because changing anything renders the whole project unstable. Often the code works, but the project is more a failure than a success because it cannot be extended or re-used. Another reason for planning is the ease of bug fixing and the costs associated with it. Open source developers often do not think about it until they start selling their services or work to commercial companies. As shown by recent studies, the cost of problem fixing grows rapidly toward the end of the project. The cost is minimal when development has not started yet, and the person in charge just collects requirements. When requirements are collected and a programmer (or a team of programmers) starts to think how to implement these requirements, a change of requirements, or fixing a problem in the requirements still does not cost much. But it may already be difficult for developers if they came to a certain implementation approach after reviewing requirements. Things become worse at the development stage. Imagine that the selected approach was wrong and it was uncovered close to the end of development. Lots of time is lost, and work may have to start from the beginning. Now imagine what happens if the project is released to the customer and the customer says that the outcome of the project does not work as expected (something was implemented differently (as compared to expectations), or something was not implemented at all). The cost of fixing is likely to be high and overshoot the budget. Next, imagine what would happen if problems occurred when a project went live. After reading the previous paragraph, some developers may ask how the situation applies to non-commercial development, as there is a false perception that there are no costs associated with it (at least, no direct costs). But, the costs exist! And often they are much more sensitive than financial costs. The cost in non-commercial development is reputation. If a developer's product does not work well or does not work at all or it has obvious flaws, the general opinion about the developer may become bad ("cannot trust his code"). Developers will also have troubles improving because often they do not understand what has gone wrong. But the answer is near. Do not rush! Plan it well! You may even think of something about the future code, and then start coding only when the picture is clear. Planning is an important part of software development. While freelancers can usually divide their time freely between planning and implementation, many corporate developers often do not have such freedom. And even worse, many managers still do not see planning as a necessary step in software development. This situation is well explained in The parable of the two programmers, which readers of this book are encouraged to read in full. When it comes to TYPO3, planning is more important than an average application. TYPO3 is very complex, and its implementation is also complex. Without planning, programmers will most likely have to change their already written code to fix unforeseen problems therefore, good planning for TYPO3 extensions is extremely important. But let us move on and see how to plan an extension. How to Plan There are several stages in planning. Typically, each stage answers one or more important questions about development. TYPO3 developers should think about at least three stages: Gathering requirements Implementation planning Documentation planning Of course, each project is unique and has other stages. But these three stages generally exist in every project. Gathering Requirements The first thing that a developer needs to know is what his/her extension will do. While it sounds pretty obvious, not many extension authors know exactly what functionality the extension has in the end. It evolves over time, and often the initial idea is completely different from the final implementation. Predictably, neither the original nor the final is done well. In the other case, when extension features are collected, though planned and implemented according to plan, they usually fit well together. So, the very first thing to do when creating an extension is to find out what that extension should do. This is called gathering requirements. For non-commercial extensions, gathering requirements simply means writing down what each extension should do. For example, for a news extension, it may be: Show list of news sorted by date Show list of latest news Show news archive Show only a small amount of text in news list view As we have seen, gathering requirements looks easier than it actually is. The process, however, may become more complex when an extension is developed for an external customer. Alan Cooper, in his famous About Face book, shows how users, architects, and developers see the same product. From the user's perspective, it looks like a perfect circle. An architect sees something closer to an octagon. A developer creates something that looks like a polygon with many segments connected at different degrees. These differences always exist and each participating party is interested in minimizing them. A developer must not be afraid of asking questions. The cleaner picture he/she has, the better he/she will understand the customer's requirements. Implementation Planning When the requirements are gathered, it is necessary to think which blocks an extension will have. It may be blocks responsible for data fetching, presentation, conversion, and so on. In the case of TYPO3 extension implementation, planning should result in a list of Frontend (FE) plugins, Backend (BE) modules, and standalone classes. The purpose of each plug-in, module, and/or class must be clear. When thinking of FE plugins, caching issues must be taken into account. While most of the output can be cached to improve TYPO3 performance, forms processing should not be cached. Some extensions completely prevent caching of the page when processing forms. But there is a better approach, a separate FE plug-in from the non-cached output. BE modules must take into account the ease of use. Standard BE navigation is not very flexible, and this must be taken into account when planning BE modules. Certain functionalities can be moved to separate classes. This includes common functions and any public APIs that an extension provides to the other extensions. Hooks or "user functions" are usually placed in separate classes depending on the functional zone or hooked class. Documentation Planning A good extension always comes with documentation. Documentation should also be planned. Typically, manuals for extensions are created using standard templates, which have standard sections defined. While this simplifies documentation writing for extension developers, they still have to plan what they will put into these sections. TYPO3-Specific Planning There are several planning issues specific to TYPO3. Developers must take care of them before the actual development. Extension Keys Each extension must have a unique key. Extension keys can be alphanumeric and contain underscore characters. It may not start with a digit, the letter u, or the test_ prefix. However, not every combination of these symbols makes a good extension key. An extension key must be descriptive but not too long. Having personal or company prefixes is not forbidden but is not recommended. Underscores should be avoided. Abbreviations should be avoided as well, because they often do not make sense for other users. Examples of good extension keys are: news comments usertracker loginbox Examples of bad extension keys are: news_extension mycorp_ustr myverygoodextensionthatdoesalotofthings mvgetdalot john_ext div2007 Database Structure Most TYPO3 extensions use a database to load and/or store their own data. Changing the data structure during application development may seriously slow down development, or may even cause damage to data if some data is already entered into the system. Therefore, it is extremely important to think about an extension's data structure well in advance. Such thinking requires knowledge about how TYPO3 database tables are organized. Tables in TYPO3 database must have certain structures to be properly managed by TYPO3. If a table does not fulfill TYPO3 requirements, users may see error messages in the BE (especially in the Web | List module), and data may become corrupted. Every record in every TYPO3 table belongs to a certain page inside TYPO3. TYPO3 has a way to identify which page the record belongs to.
Read more
  • 0
  • 0
  • 1502
article-image-blender-3d-interview-allan-brito
Packt
23 Oct 2009
8 min read
Save for later

Blender 3D: Interview with Allan Brito

Packt
23 Oct 2009
8 min read
Meeba Abraham: Hi Allan, thank you for talking to us today, why don’t you tell us a bit about yourself and your background; how did you start working with Blender? Allan Brito: Hi, and thanks for this opportunity to talk a bit about myself. Well, I’m a 29 year-old architect from Brazil. After my graduation, I started working on visualization projects, mostly on 3ds Max for a small studio here in Brazil. After two years I started teaching 3D modeling and animation and I fell in love with teaching. I still teach 3D animation and modeling at a College here. With the help of my teaching experience, I began writing manuals and tutorials about 3D animation. Eventually, I decided to write a book about Blender in Portuguese, and the book was a huge success in Brazil. Currently I`m working on the third edition of this book. With the book, I also needed a way to keep in touch with the readers and discuss about Blender and 3D related stuff. So I started a web site (www.allanbrito.com), where I regularly write short articles and tutorials about Blender and its comparison with other 3D packages. Today the web site has grown considerably, and I continue to update it with content on Blender and other 3D software tools. Meeba Abraham: How long have you been working with it? Allan Brito: My first contact with Blender 3D was in 2003. I was invited by a friend to check out a great open source software for 3D visualization. I was really impressed by Blender, its potential, and the lightweight of the software. Coming from a 3ds Max background, it was a bit hard to get used to the interface and the keyboard shortcuts, but after a few weeks I started getting used to it. After the learning process, I started to use Blender as the main tool for my projects. I can`t say that it was easy to use at first, but with time Blender simply grew on me and became my main tool for my projects. Meeba Abraham: Can you tell about some of the key features of Blender that makes it a viable option to other professional 3D software? Allan Brito: There are many features in Blender that other professional 3D suites do not have. For instance, the integrated Game Engine, which allows you to produce interactive animations, is just awesome! For 3D modeling, Blender has a sculpt module where artists can create 3D models only by sculpt geometry in a way similar to what sculpting tools such as ZBrush and MudBox provides. The node editor in Blender is also an incredible tool to create materials and for post-production. Post-production is a powerful tool in Blender. There is a sequencer editor that works like a video editor. You can cut, join, and post-process videos in the sequence editor. For instance, an animator can create a full animation without the need of any other software. Recently, the Big Buck Bunny project introduced some great tools for character animation in Blender, like better fur, a new and improved particle system, new and improved UV Mapping and much more. I strongly recommend a visit to www.blender.org to check out the full list of features, which is huge. Meeba Abraham: Why is Blender an important 3D application that an aspiring graphics artist should consider using? Allan Brito: I believe that Blender has a great set of features that can help a graphic artist create some impressive art work. Why Blender? I guess the best answer is; why not? All the features offered by other 3D animation software are also available in Blender, such as character animation, physics simulation, particle animation, and much more. And with Blender being a free software, you won’t have to get a single license and be bounded to only one workstation. Besides the features, I believe in the community nature of Blender. If you feel a tool or feature is missing, just make a suggestion to the community or make the feature yourself! Meeba Abraham: Over the years, Blender has grown in popularity. What, in your opinion, are some of the main reasons for this? Allan Brito: In the last few years Blender gained many features that only the so-called high-end and expansive 3D software had. This puts the spotlight right into Blender, and some old and experienced professionals are using Blender today, to take a look at these advanced features, and they like it. Besides the features, the Blender Foundation is doing a great job by supporting Blender and promoting it outside the community. They organize conferences and projects to show the potentials of Blender as a 3D animation package. The last open movie—Big Buck Bunny—supported by the community is a great example of that. Meeba Abraham: Since Blender is an open source 3D application, the Blender community plays an important role in its growth. Can you shed some light on the blender community? How have they helped to popularize Blender? Allan Brito: What can I say? The Blender community is great and has been supporting the development of Blender for a long time. The last open movie is a great example of what this community can do. Big Buck Bunny is a project mainly created by the Blender community. Artists could buy the DVD of the animation even before the project started. And when the animation was finished, all Blender users could buy a shiny DVD of the animation that contains tutorials and all source files of the animation. Now, what if Pixar gave away all the production files of their animations. And even of you don’t want to buy the DVD, you can still download all of the content for free from the project Web site, www.bigbuckbunny.org. This is a great example of the Blender community spirit and how much support Blender gets from around the world. Meeba Abraham: You have just authored a book on Blender; how did you find the experience? Is this the first book you’ve written? Allan Brito: Writing a book on Blender was quite a challenge for me. Even with the experience of writing tutorials and short articles about Blender, writing a book was not easy! But after a few weeks, I was able to write the chapters naturally and almost on schedule. The biggest challenge for me was to write about a subject that no one else had written about yet. In my first book “Blender 3D – Guia do Usuário” written in Brazilian Portuguese, the challenge was even bigger. When I started writing that book, there weren’t any updated documentation on Blender features. So I had to do a lot of research myself. With this book, the challenge again was to write about something that no one else has ever written. Even with a few short tutorials around, there weren`t any full set of procedures or tips for working with architectural visualization in Blender. The experience was great and I hope this is just the first book in a long series of books! I have a few ideas for writing more books about Blender and I’m already working on some of them. Meeba Abraham: How do you anticipate it will help the Blender community? Is it different to other Blender books? Allan Brito: I believe that a lot of users want to use Blender for architectural visualization but have only found tutorials and books on character modeling and animation. This book was written with architectural visualization in mind. So every example and Blender tool is described specifically with architectural examples. Meeba Abraham: You make regular contributions to www.BlenderNation.com, how did you get involved with the site and what does it offer to the community? Allan Brito: BlenderNation is the comprehensive Web site for Blender related news. So if anyone is curious about what`s going on in the Blender community, the first place to look after the Foundation Web site is BlenderNation. My involvement with BlenderNation began with my writing articles about Blender in Brazilian Portuguese for my own web site (www.allanbrito.com). A few months later, I was invited by Bart Veldhuizen to write a few tutorials and I guess they liked my work! After that I was writing articles for BlenderNation as a Contributor Editor. And I have to say that it`s really great to be a part of it, and keep the Blender community updated. The experience with BlenderNation and the books inspired me to start a new project called Blender 3D Architect (www.blender3darchitect.com) where I write articles on how to use Blender for architectural visualization along with tips and tutorials. Meeba Abraham: Thanks for your time and contributions!
Read more
  • 0
  • 0
  • 3825

article-image-openfire-effectively-managing-users
Packt
23 Oct 2009
14 min read
Save for later

Openfire: Effectively Managing Users

Packt
23 Oct 2009
14 min read
Despite the way it sounds, managing users isn't an all-involving activity—at least it shouldn't be. Most system administrators tend to follow the "install-it-forget-it" methodology to running their servers. You can do so with Openfire as well, but with a user-centeric service such as an IM server, keeping track of things isn't a bad idea. Openfire makes your job easier with its web-based admin interface. There are several things that you can setup via the web interface that'll help you manage the users. You can install some plugins that'll help you run and manage the server more effectively, such as the plugin for importing/exporting users, and dual-benefit plugins such as the search plugin, which help users find other users in the network, and also let you check up on users using the IM service. In this article, we will cover: Searching for users Getting email alerts via IM Broadcasting messages to all users Managing user clients Importing/exporting users Searching for Users with the SearchPlugin Irrespective of whether you have pre-populated user rosters, letting users find other users on the network is always a good idea. The Search Plugin works both ways—it helps your users find each other, and also helps you, the administrator, to find users and modify their settings if required. To install the plugin, head over to the Plugins tab (refer to the following screenshot). The Search plugin is automatically installed along with Openfire, and will be listed as a plugin that is already installed. It's still a good idea to restart the plugin just to make sure that everything's ok. Locate and click the icon in the Restart column that corresponds to the Search plugin. This should restart the plugin. The Search plugin has various configurable options, but by default the pluginis deployed with all of its features enabled. So your users can immediately start searching for users. To tweak the Search plugin options, head over to the Server | Server Settings |Search Service Properties in the Openfire admin interface. From this page, you can enable or disable the service. Once enabled, users will be able to search for other users on the network from their clients. Not all clients have the Search feature but Spark, Exodus, Psi, and some others do. Even if you disable this plugin, you, the admin, will still be able to search for users from the Openfire admin interface as described in the following section. In addition to enabling the Search option, you'll have to name it. The plugin is offered as a network "service" to the users. The Openfire server offers other services and also includes the group chat feature which we will discuss in the Appendix. Calling the search service by its default name, search.< your-domain-name > is a goodidea. You should only change it if you have another service on your network with the same name. Finally, you'll have to select the fields users can search on. The three options available are Username, Name, and Email (refer to the previous screenshot). You can enable any of these options, or all the three for a better success rate. Once you're done with setting up the options, click the Save Properties button to apply them. To use the plugin, your users will have to use their clients to query the Openfire server and then select the search service from the ones listed. This will present them with a search interface through which they'll be able to search for their peers(refer to the following screenshot) using one or more of the three options (Username,Name, Email), depending on what you have enabled. Searching for Users from Within The Admin Interface So we've let our users look for their peers, but how do you, the Openfire admin, look for users? You too can use your client, but it's better to do it from the interface since you can tweak the user's settings from there as well. To search for users from within the admin interface, head over to the Users/Groups tab. You'll notice an AdvancedUser Search option in the sidebar. When you click on this option, you'll be presented with a single text field withthree checkboxes (refer to the previous screenshot). In the textfield, enter the user'sName, Username, and Email that you want to find. The plugin can also handle the * wildcard character so that you can search using a part of the user's details as well.For example, if you want to find a user "James", but don't know if his last name isspelled "Allen" or "Allan", try entering "James A*" in the search field and make sure that the Name checkbox is selected. Another example would be "* Smith", which looks for all the users with the last name "Smith". The search box is case-sensitive. So why were you looking for "James Allan", the guy with two first names? It was because his last name is in fact "Allen" and he wants to get it corrected. So you find his record with the plugin and click on his username. This brings up a summary of his properties including his status, the groups he belongs to, when he was registeredon the network, and so on. Find and click the Edit Properties button below the details, make the required changes, and click the Save Properties > button. Get Email Alerts via IM Instant Messaging is an alternate line of enterprise communication, along with electronic ones such as email and traditional ones such as the telephone. Some critical tasks require instant notification and nothing beats IM when it comes to time-critical alerts. For example, most critical server software applications, especially the ones facing outwards on to the Internet, are configured to send an email to the admin in case of an emergency—for example, a break-in attempt, abnormal shutdown, hardware failure, and so on. You can configure Openfire to route these messages to you as an IM, if you're online. If you're a startup that only advertises a single info@coolstartup.com email address which is read by all seven employees of the company, you can configure Openfire to send IMs to all of you when the VCs come calling! Setting this up isn't an issue if you have the necessary settings handy. The email alert service connects to the email server using IMAP and requires the following options: Mail Host: The host running the email service. Example: imap.example.com Mail Port: The port through which Openfire listens for new email. SSL can also be used if it is enabled on your mail server. Example: 993. Server Username: The username of the account you want to monitor.Example: info@cool-startup.com. Server Password: The accounts password. Folder: The folder in which Openfire must look for new messages. Typically this will be the "Inbox" but if your server filters email that meet a preset criteria into a particular folder, you need to specify it here. Check Frequency: How frequently Openfire should check the account for new email. The default value is 300000 ms which is equal to 5 minutes. JID of users to notify: This is where you specify the Openfire Jabber IDs(userids) of the users you want to notify when a new email pops up. If you need to alert multiple users, separate their JID's with commas. But first head over to the Plugins tab and install the Email Listener plugin from the list of available plugins. Once you have done this, head back to the Server tab and choose the Email Listener option in the sidebar and enter the settings in the form that pops up (refer to the following screenshot). Click the Test Settings button to allow Openfire to try to connect to the server using the settings provided. If the test is successful, finish off the setup procedure by clicking the Save button to save your settings. If the test fails, check the settings and make sure that the email server is up and running. You can test and hook them with your Gmail account as well. That's it. Now close that email client you have running in the background, and let Openfire play secretary, while you write your world domination application! Broadcasting Messages Since Openfire is a communication tool, it reserves the coolest tricks in the bag for that purpose. The primary purpose of Openfire remains one-to-one personal interactions and many-to-many group discussion, but it can also be used as a one-to-many broadcasting tool. This might sound familiar to you. But don't sweat, I'm not repeating myself. The one-to-many broadcasting we cover in this section is different from the Send Message tool. The Send Message tool from the web-based Openfire administration console is available only to the Openfire administrator. But the plugin we cover in this section has a much broader perspective. For one, the Broadcast plugin can be used by non-admin users, though of course, you can limit access. Secondly, the Broadcast plugin can be used to send messages to a select group of users which can grow to include everyone in the organization using Openfire. One use of the broadcast plugin is for sending important reminders. Here are some examples: The Chief Accounts Officer broadcasts a message to everyone in the organization reminding them to file their returns by a certain date. The CEO broadcasts a message explaining the company's plans to merge with or acquire another company, or just to share a motivational message. You, the Openfire administrator, use the plugin to announce system outages. The Sales Department Head is upset because sales targets haven't been met and calls for a group meeting at 10:00 a.m. on the day after tomorrow and in forms everyone in the Sales department via the plugin. The intern in the advertisement department sends a list of his accounts to everyone in the department before returning to college and saves everyone a lot of running around, thanks to the plugin. Setting up the Plugin To reap the benefits of the Broadcast plugin, begin by installing it from under theAvailable Plugins list on the Plugins tab. This plugin has a few configuration options which should be set carefully—using a misconfigured broadcast plugin, the new guy in the purchase department could send a message of "Have you seen my stapler?" to everyone in the organization, including the CEO! The broadcast plugin is configured via the Openfire system properties. Remember these? They are listed under the Server tab's System Properties option in the sidebar. You'll have to manually specify the settings using properties (refer to the following screenshot): plugin.broadcast.serviceName— This is the name of the broadcast service. By default, the service is called "broadcast", but you can call it something else, such as "shout", or "notify". plugin.broadcast.groupMembersAllowed— This property accepts two values—true and false. If you select the "true" option, all group members will be allowed to broadcast messages to all users in the group they belong to. If set to "false", only group admins can send messages to all members of their groups. The default value is "true". plugin.broadcast.disableGroupPermissions— Like the previous property, this property also accepts either true or false values. By selecting the "true" option, you will allow any user in the network to broadcast messages to any group and vice versa, the "false" option restricts the broadcasting option to group members and admins. The default value of this group is "false". As you can imagine, if you set this value to "true" and allow anyone to send broadcast messages to a group, you effectively override the restrictive value of the previous setting. plugin.broadcast.allowedUsers—Do not forget to set this property! If it is not set, anyone on the network can send a message to everyone else on the network. There are a only a few people you'd want to have the ability to broadcast a message to everyone in the organization. This list of users who can talk to everyone should be specified with this property by a string of comma-separated JIDs. In most cases, the default options of these properties should suffice. If you don't change any variables, your service will be called "broadcast" and will allow group members to broadcast messages to their own groups and not to anyone else. You should also add the JIDs of executive members of the company (CEO, MD, etc.) to the list of users allowed to send messages to everyone in the organization. Using The Plugin Once you have configured the plugin, you'll have to instruct users on how to use the plugin according to the configuration. To send a message using the broadcast plugin, users must add a user with the JID in the following format @. (refer to the following screenshot). If the CEO wants to send a message to everyone, he has to send it to a user called all@broadcast.serverfoo, assuming that you kept the default settings, and that your Openfire server is called serverfoo. Similarly, when members of the sales department want to communicate with their departmental collegues, they have to send the message to sales@broadcast.serverfoo. Managing User Clients There's no dearth of IM clients. It's said that if you have ten users on your network, you'll have at least fifteen different clients. Managing user's clients is like bringing order to chaos. In this regard you'll find that Openfire is biased towards its own IMclient, Spark. But as it has all the features you'd expect from an IM client and runs on multiple platforms as well, one really can't complain. So what can you control using the client control features? Here's a snapshot: Don't like users transferring files? Turn it off, irrespective of the IM client. Don't like users experimenting with clients? Restrict their options Don't want to manually install Spark on each and every user's desktop? Put it on the network, and send them an email with a link, along with installation and sign-in instructions. Do users keep forgetting the intranet website address? Add it as a bookmark in their clients. Don't let users bug you all the time asking for the always-on "hang-out"conference room. Add it as a bookmark to their client! Don't these features sound as if they can take some of the work off your shoulders? Sure, but you'll only truly realize how cool and useful they are when you implement them! So what are you waiting for? Head over to the Plugins tab and install the Client Control plugin. When it is installed, head over to the Server | ClientManagement tab. Here you'll notice several options. The first option under client management, Client Features, lets you enable or disable certain client features (refer to the following screenshot). These are: Broadcasting: If you don't want your users to broadcast messages, disable this feature. This applies only to Spark. File Transfer: Disabling this feature will stop your users from sharing files.This applies to all IM clients. Avatar/VCard: You can turn off indiscriminate changes to a user's avatar or virtual visiting card by disabling this experimental feature which only applies to Spark. Group Chat: Don't want users to join group chat rooms? Then disable this feature which will prevent all the users from joining discussion groups, irrespective of the IM client they are using. By default, all of these features are enabled. When you've made changes as per your requirements, remember to save the settings using the Save Settings button. Next, head over to the Permitted Clients option (refer to the following screenshot) to restrict the clients that users can employ. By default, Openfire allows all XMPPclients to connect to the server. If you want to run a tight ship, you can decide to limit the number of clients allowed by selecting the Specify Clients option button. From the nine clients listed for the three platforms supported by Openfire (Windows,Linux, and Mac), choose the clients you trust by selecting the checkbox next to them.If your client isn't listed, use the Add Other Client text box to add that client. When you've made your choices, click on the Save Settings button to save and implement the client control settings. The manually-added clients are automatically added to the list of allowed clients. If you don't trust them, why add them? The remove link next to these clients will remove them from the list of clients you trust.
Read more
  • 0
  • 0
  • 5919

article-image-troubleshooting-lotus-notesdomino-7-applications
Packt
23 Oct 2009
19 min read
Save for later

Troubleshooting Lotus Notes/Domino 7 applications

Packt
23 Oct 2009
19 min read
Introduction The major topics that we'll cover in this article are: Testing your application (in other words, uncovering problems before your users do it for you). Asking the right questions when users do discover problems. Using logging to help troubleshoot your problems. We'll also examine two important new Notes/Domino 7 features that can be critical for troubleshooting applications: Domino Domain Monitoring (DDM) Agent Profiler   For more troubleshooting issues visit: TroubleshootingWiki.org Testing your Application Testing an application before you roll it out to your users may sound like an obvious thing to do. However, during the life cycle of a project, testing is often not allocated adequate time or money. Proper testing should include the following: A meaningful amount of developer testing and bug fixing: This allows you to catch most errors, which saves time and frustration for your user community. User representative testing: A user representative, who is knowledgeable about the application and how users use it, can often provide more robust testing than the developer. This also provides early feedback on features. Pilot testing: In this phase, the product is assumed to be complete, and a pilot group uses it in production mode. This allows for limited stress testing as well as more thorough testing of the feature set. In addition to feature testing, you should test the performance of the application. This is the most frequently skipped type of testing, because some consider it too complex and difficult. In fact, it can be difficult to test user load, but in general, it's not difficult to test data load. So, as part of any significant project, it is a good practice to programmatically create the projected number of documents that will exist within the application, one or two years after it has been fully deployed, and have a scheduled agent trigger the appropriate number of edits-per-hour during the early phases of feature testing. Although this will not give a perfect picture of performance, it will certainly help ascertain whether and why the time to create a new document is unacceptable (for example, because the @Db formulas are taking too long, or because the scheduled agent that runs every 15 minutes takes too long due to slow document searches). Asking the Right Questions Suppose that you've rolled out your application and people are using it. Then the support desk starts getting calls about a certain problem. Maybe your boss is getting an earful at meetings about sluggish performance or is hearing gripes about error messages whenever users try to click a button to perform some action. In this section, we will discuss a methodology to help you troubleshoot a problem when you don't necessarily have all the information at your disposal. We will include some specific questions that can be asked verbatim for virtually any application. The first key to success in troubleshooting an application problem is to narrow down where and when it happens. Let's take these two very different problems suggested above (slow performance and error messages), and pose questions that might help unravel them: Does the problem occur when you take a specific action? If so, what is that action? Your users might say, "It's slow whenever I open the application", or "I get an error when I click this particular button in this particular form". Does the problem occur for everyone who does this, or just for certain people? If just certain people, what do they have in common? This is a great way to get your users to help you help them. Let them be a part of the solution, not just "messengers of doom". For example, you might ask questions such as, "Is it slow only for people in your building or your floor? Is it slow only for people accessing the application remotely? Is it slow only for people who have your particular access (for example, SalesRep)?" Does this problem occur all the time, at random times, or only at certain times? It's helpful to check whether or not the time of day or the day of week/month is relevant. So typical questions might be similar to the following: "Do you get this error every time you click the button or just sometimes? If just sometimes, does it give you the error during the middle of the day, but not if you click it at 7 AM when you first arrive? Do you only get the error on Mondays or some other day of the week? Do you only see the error if the document is in a certain status or has certain data in it? If it just happens for a particular document, please send me a link to that document so that I can inspect it carefully to see if there is invalid or unexpected data." Logging Ideally, your questions have narrowed down the type of problem it could be. So at this point, the more technical troubleshooting can start. You will likely need to gather concrete information to confirm or refine what you're hearing from the users. For example, you could put a bit of debugging code into the button that they're clicking so that it gives more informative errors, or sends you an email (or creates a log document) whenever it's clicked or whenever an error occurs. Collecting the following pieces of information might be enough to diagnose the problem very quickly: Time/date User name Document UNID (if the button is pushed in a document) Error Status or any other likely field that might affect your code By looking for common denominators (such as the status of the documents in question, or access or roles of the users), you will likely be able to further narrow down the possibilities of why the problem is happening. This doesn't solve your problem of course, but it helps in advancing you a long way towards that goal. A trickier problem to troubleshoot might be one we mentioned earlier: slow performance. Typically, after you've determined that there is some kind of performance delay, it's a good idea to first collect some server logging data. Set the following Notes.ini variables in the Server Configuration document in your Domino Directory, on the Notes.ini tab: Log_Update=1Log_AgentManager=1 These variables instruct the server to write output to the log.nsf database in the Miscellaneous Events view. Note that they may already be set in your environment. If not, they're fairly unobtrusive, and shouldn't trouble your administration group. Set them for a 24-hour period during a normal business week, and then examine the results to see if anything pops out as being suspicious. For view indexing, you should look for lines like these in the Miscellaneous Events (Log_Update=1): 07/01/2006 09:29:57 AM Updating views in appsSalesPipeline.nsf07/01/2006 09:30:17 AM Finished updating views in appsSalesPipeline.nsf07/01/2006 09:30:17 AM Updating views in appsTracking.nsf07/01/2006 09:30:17 AM Finished updating views in appsTracking.nsf07/01/2006 09:30:17 AM Updating views in appsZooSchedule.nsf07/01/2006 09:30:18 AM Finished updating views in appsZooSchedule.nsf And lines like these for Agent execution (Log_AgentManager=1): 06/30/2006 09:43:49 PM AMgr: Start executing agent 'UpdateTickets' in 'appsSalesPipeline.nsf ' by Executive '1'06/30/2006 09:43:52 PM AMgr: Start executing agent 'ZooUpdate' in 'appsZooSchedule.nsf ' by Executive '2'06/30/2006 09:44:44 PM AMgr: Start executing agent 'DirSynch' in 'appsTracking.nsf ' by Executive '1' Let's examine these lines to see whether or not there is anything we can glean from them. Starting with the Log_Update=1 setting, we see that it gives us the start and stop times for every database that gets indexed. We also see that the database file paths appear alphabetically. This means that, if we search for the text string updating views and pull out all these lines covering (for instance) an hour during a busy part of the day, and copy/paste these lines into a text editor so that they're all together, then we should see complete database indexing from A to Z on your server repeating every so often. In the log.nsf database, there may be many thousands of lines that have nothing to do with your investigation, so culling the important lines is imperative for you to be able to make any sense of what's going on in your environment. You will likely see dozens or even hundreds of databases referenced. If you have hundreds of active databases on your server, then culling all these lines might be impractical, even programmatically. Instead, you might focus on the largest group of databases. You will notice that the same databases are referenced every so often. This is the Update Cycle, or view indexing cycle. It's important to get a sense of how long this cycle takes, so make sure you don't miss any references to your group of databases. Imagine that SalesPipeline.nsf and Tracking.nsf were the two databases that you wanted to focus on. You might cull the lines out of the log that have updating views and which reference these two databases, and come up with something like the following: 07/01/2006 09:29:57 AM Updating views in appsSalesPipeline.nsf07/01/2006 09:30:17 AM Finished updating views in appsSalesPipeline.nsf07/01/2006 09:30:17 AM Updating views in appsTracking.nsf07/01/2006 09:30:20 AM Finished updating views in appsTracking.nsf07/01/2006 10:15:55 AM Updating views in appsSalesPipeline.nsf07/01/2006 10:16:33 AM Finished updating views in appsSalesPipeline.nsf07/01/2006 10:16:33 AM Updating views in appsTracking.nsf07/01/2006 10:16:43 AM Finished updating views in appsTracking.nsf07/01/2006 11:22:31 AM Updating views in appsSalesPipeline.nsf07/01/2006 11:23:33 AM Finished updating views in appsSalesPipeline.nsf07/01/2006 11:23:33 AM Updating views in appsTracking.nsf07/01/2006 11:23:44 AM Finished updating views in appsTracking.nsf This gives us some very important information: the Update task (view indexing) is taking approximately an hour to cycle through the databases on the server; that's too long. The Update task is supposed to run every 15 minutes, and ideally should only run for a few minutes each time it executes. If the cycle is an hour, then that means update is running full tilt for that hour, and as soon as it stops, it realizes that it's overdue and kicks off again. It's possible that if you examine each line in the log, you'll find that certain databases are taking the bulk of the time, in which case it might be worth examining the design of those databases. But it might be that every database seems to take a long time, which might be more indicative of a general server slowdown. In any case, we haven't solved the problem; but at least we know that the problem is probably server-wide. More complex applications, and newer applications, tend to reflect server‑performance problems more readily, but that doesn't necessarily mean they carry more responsibility for the problem. In a sense, they are the "canary in the coal mine". If you suspect the problem is confined to one database (or a few), then you can increase the logging detail by setting Log_Update=2. This will give you the start time for every view in every database that the Update task indexes. If you see particular views taking a long time, then you can examine the design of those views. If no database(s) stand out, then you might want to see if the constant indexing occurs around the clock or just during business hours. If it's around the clock, then this might point to some large quantities of data that are changing in your databases. For example, you may be programmatically synchronizing many gigabytes of data throughout the day, not realizing the cost this brings in terms of indexing. If slow indexing only occurs during business hours, then perhaps the user/data load has not been planned out well for this server. As the community of users ramps up in the morning, the server starts falling behind and never catches up until evening. There are server statistics that can help you determine whether or not this is the case. (These server statistics go beyond the scope of this book, but you can begin your investigation by searching on the various Notes/Domino forums for "server AND performance AND statistics".) As may be obvious at this point, troubleshooting can be quite time-consuming. The key is to make sure that you think through each step so that it either eliminates something important, or gives you a forward path. Otherwise, you can find yourself still gathering information weeks and months later, with users and management feeling very frustrated. Before moving on from this section, let's take a quick look at agent logging. Agent Manager can run multiple agents in different databases, as determined by settings in your server document. Typically, production servers only allow two or three concurrent agents to run during business hours, and these are marked in the log as Executive '1', Executive '2', and so on. If your server is often busy with agent execution, then you can track Executive '1' and see how many different agents it runs, and for how long. If there are big gaps between when one agent starts and when the next one does (for Executive '1'), this might raise suspicion that the first agent took that whole time to execute. To verify this, turn up the logging by setting the Notes.ini variable debug_amgr=*. (This will output a fair amount of information into your log, so it's best not to leave it on for too long, but normally one day is not a problem.) Doing this will give you a very important piece of information: the number of "ticks" it took for the agent to run. One second equals 100 ticks, so if the agent takes 246,379 ticks, this equals 2,463 seconds (about 41 minutes). As a general rule, you want scheduled agents to run in seconds, not minutes; so any agent that is taking this long will require some examination. In the next section, we will talk about some other ways you can identify problematic agents. Domino Domain Monitoring (DDM) Every once in a while, a killer feature is introduced—a feature so good, so important, so helpful, that after using it, we just shake our heads and wonder how we ever managed without it for so long. Domino Domain Monitor (DDM) is just such a feature. DDM is too large to be completely covered in this one section, so we will confine our overview to what it can do in terms of troubleshooting applications. For a more thorough explanation of DDM and all its features, see the book, Upgrading to Lotus Notes and Domino (www.packtpub.com/upgrading_lotus/book). In the events4.nsf database, you will find a new group of documents you can create for tracking agent or application performance. On Domino 7 servers, a new database is created automatically with the filename ddm.nsf. This stores the DDM output you will examine. For application troubleshooting, some of the most helpful areas to track using DDM are the following: Full-text index needs to be built. If you have agents that are creating a full‑text index on the fly because the database has no full‑text index built, DDM can track that potential problem for you. Especially useful is the fact that DDM compiles the frequency per database, so (for instance) you can see if it happens once per month or once per hour. Creating full‑text indexes on the fly can result in a significant demand on server resources, so having this notification is very useful. We discuss an example of this later in this section. Agent security warnings. You can manually examine the log to try to find errors about agents not being able to execute due to insufficient access. However, DDM will do this for you, making it much easier to find (and therefore fix) such problems. Resource utilization. You can track memory, CPU, and time utilization of your agents as run by Agent Manager or by the HTTP task. This means that at any time you can open the ddm.nsf database and spot the worst offenders in these categories, over your entire server/domain. We will discuss an example of CPU usage later in this section. The following illustration shows the new set of DDM views in the events4.nsf (Monitoring configuration) database: The following screenshot displays the By Probe Server view after we've made a few document edits: Notice that there are many probes included out-of-the-box (identified by the property "author = Lotus Notes Template Development") but set to disabled. In this view, there are three that have been enabled (ones with checkmarks) and were created by one of the authors of this book. If you edit the probe document highlighted above, Default Application Code/Agents Evaluated By CPU Usage (Agent Manager), the document consists of three sections. The first section is where you choose the type of probe (in this case Application Code) and the subtype (in this case Agents Evaluated By CPU Usage). The second section allows you to choose the servers to run against, and whether you want this probe to run against agents/code executed by Agent Manager or by the HTTP task (as shown in the following screenshot). This is an important distinction. For one thing, they are different tasks, and therefore one can hit a limit while the other still has room to "breathe". But perhaps more significantly, if you choose a subtype of Agents Evaluated By Memory Usage, then the algorithms used to evaluate whether or not an agent is using too much memory are very different. Agents run by the HTTP task will be judged much more harshly than those run by the Agent Manager task. This is because with the HTTP task, it is possible to run the same agent with up to hundreds of thousands of concurrent executions. But with Agent Manager, you are effectively limited to ten concurrent instances, and none within the same database. The third section allows you to set your threshold for when DDM should report the activity: You can select up to four levels of warning: Fatal, Failure, Warning (High), and Warning (Low). Note that you do not have the ability to change the severity labels (which appear as icons in the view). Unless you change the database design of ddm.nsf, the icons displayed in the view and documents are non-configurable. Experiment with these settings until you find the approach that is most useful for your corporation. Typically, customers start by overwhelming themselves with information, and then fine-tuning the probes so that much less information is reported. In this example, only two statuses are enabled: one for six seconds, with a label of Warning (High), and one for 60 seconds, with a label of Failure. Here is a screenshot of the DDM database: Notice that there are two Application Code results, one with a status of Failure (because that agent ran for more than 60 seconds), and one with a status of Warning (High) (because that agent ran for more than six seconds but less than 60 seconds). These are the parameters set in the Probe document shown previously, which can easily be changed by editing that Probe document. If you want these labels to be different, you must enable different rows in the Probe document. If you open one of these documents, there are three sections. The top section gives header information about this event, such as the server name, the database and agent name, and so on. The second section includes the following table, with a tab for the most recent infraction and a tab for previous infractions. This allows you to see how often the problem is occurring, and with what severity. The third section provides some possible solutions, and (if applicable) automation. For example, in our example, you might want to "profile" your agent. (We will profile one of our agents in the final section of this article.) DDM can capture full-text operations against a database that is not full‑text indexed. It tracks the number of times this happens, so you can decide whether to full‑text index the database, change the agent, or neither. For a more complete list of the errors and problems that DDM can help resolve, check the Domino 7 online help or the product documentation (www.lotus.com). Agent Profiler If any of the troubleshooting tips or techniques we've discussed in this article causes you to look at an agent and think, "I wonder what makes this agent so slow", then the Agent Profiler should be the next tool to consider. Agent Profiler is another new feature introduced in Notes/Domino 7. It gives you a breakdown of many methods/properties in your LotusScript agent, telling you how often each one was executed and how long they took to execute. In Notes/Domino 7, the second (security) tab of Agent properties now includes a checkbox labeled Profile this agent. You can select this option if you want an agent to be profiled. The next time the agent runs, a profile document in the database is created and filled with the information from that execution. This document is then updated every time the agent runs. You can view these results from the Agent View by highlighting your agent and selecting Agent | View Profile Results. The following is a profile for an agent that performed slow mail searches: Although this doesn't completely measure (and certainly does not completely troubleshoot) your agents, it is an important step forward in troubleshooting code. Imagine the alternative: dozens of print statements, and then hours of collating results! Summary In closing, we hope that this article has opened your eyes to new possibilities in troubleshooting, both in terms of techniques and new Notes/Domino 7 features. Every environment has applications that users wish ran faster, but with a bit of care, you can troubleshoot your performance problems and find resolutions. After you have your servers running Notes/Domino 7, you can use DDM and Agent Profiler (both exceptionally easy to use) to help nail down poorly performing code in your applications. These tools really open a window on what had previously been a room full of mysterious behavior. Full-text indexing on the fly, code that uses too much memory, and long running agents are all quickly identified by Domino Domain Monitoring (DDM). Try it!
Read more
  • 0
  • 0
  • 3072
article-image-python-ldap-applications-extra-ldap-operations-and-ldap-url-library
Packt
23 Oct 2009
10 min read
Save for later

Python LDAP applications - extra LDAP operations and the LDAP URL library

Packt
23 Oct 2009
10 min read
This is the third article in the article mini-series on Python LDAP applications by Matt Butcher. The first part deals with the installation and configuration of Python-LDAP library, and the binding-unbinding operations, and changing of the LDAP password. The second article takes a look at some of LDAP operations. In this article we will see some more LDAP operations such as add operation, delete operation etc. Then we will take a look at LDAP URL Library. The ModRDN Operation Another simple write operation that can be done through the Python-LDAP API is the ModRDN operation. This operation is used to change the relative DN (RDN) of a record. We can change an RDN using the modrdn() or modrdn_s() method. These two methods take three parameters: The full DN The new RDN An optional flag indicating whether the attribute corresponding to the RDN should be deleted from the record For example, if we want to change the UID attribute for uid=manny,ou=users,dc=example,dc=com, we will need to use a ModRDN operation, since this attribute is used in the DN. Here's an example for changing the UID from manny to immanuel. >>> l.modrdn_s('uid=manny,ou=users,dc=example,dc=com',... 'uid=immanuel', False)(109, [])>>> l.compare_s('uid=immanuel,ou=users,dc=example,dc=com','uid',... 'immanuel')1>>> In this example, we first use modrdn_s() to change the DN of a record from uid=manny,ou=users,dc=example,dc=com to uid=immanuel,ou=users,dc=example,dc=com. The False flag at the end of the modrdn_s() method indicates that the old UID (uid=manny) should be left in the record. The LDIF for uid=immanuel's record now, after the ModRDN operation, looks something like this: dn: uid=immanuel,ou=Users,dc=example,dc=comcn: Manny KantgivenName: MannyobjectClass: personobjectClass: organizationalPersonobjectClass: inetOrgPersonou: Userssn: Kantuid: immanueluid: manny If we had set the last flag to True instead of False, the manny attribute value of uid would have been deleted. More sophisticated DN modifications can be made with the rename() and rename_s() methods. But your OpenLDAP server will need to be running the HDB backend for all of the renaming features to work. The Add Operation The LDAP add operation is used to add new (complete) records to the directory information tree. Here, we will look at adding records through the add() and add_s() methods of the LDAPObject class. Both of these methods take only two parameters: The string DN of the new record A list of attribute tuples While the first parameter is straightforward, we've looked at dozens of DNs already; the second attribute is a little trickier. The addition list looks something like this: add_record = [ ('objectclass', ['person','organizationalperson','inetorgperson']), ('uid', ['francis']), ('cn', ['Francis Bacon'] ), ('sn', ['Bacon'] ), ('userpassword', ['secret']), ('ou', ['users'])] If there is only one value in the attribute value list, the value can be just a string – it need not be a list. Example: ('ou', 'user') is an acceptable alternative to ('ou', ['user']). The list of attributes is made up of two-value tuples, where the first item of each tuple is the attribute name, and the second value is a list of attribute values. All of the values are expected to be strings. If you have values in a dictionary, where the attribute name is the key and the attribute values are stored in a list in the dictionary value, you can use the ldap.modlist module's addModList() function to create an attributes list in the form specified above. Once you have a list in the correct format, writing it to the directory is just a matter of executing the add() or add_s() method. >>> l.add_s('uid=francis,ou=users,dc=example,dc=com', add_record)(105, [])>>> This line performs an LDAP add operation, sending this new data to the server. The server ensures that the new record adheres to the appropriate schemas (e.g. the schemas for the person, organizationalPerson, and inetOrgPerson object classes), and then writes the entry to the directory. As might be expected, the add() method functions the same way that the add_s() method does, except that it returns an ID number. The result must be retrieved using the result() method. We can dump the new entry from the server (using the dump_record.py program developed earlier in the series) to verify that the record is as we expect it to be: $ ./dump_record.py 'uid=matt,ou=users,dc=example,dc=com' 'uid=francis, ou=users,dc=example,dc=com'Password for uid=matt,ou=users,dc=example,dc=com:dn: uid=francis,ou=users,dc=example,dc=comcn: Francis BaconobjectClass: personobjectClass: organizationalPersonobjectClass: inetOrgPersonou: userssn: Baconuid: francisuserPassword: secret We can tell by comparing this record with the add_record list above that the record is correct. The main error encountered when adding is violating the schema, either by adding attributes that are not supported, or by failing to add required attributes. When one of these conditions is met, an exception will be raised. For example, if no structural object class is specified in the attributes, an OTHER exception will be raised. If a record does not contain the attributes used in the UID, a NAMING_VIOLATION will be raised. If a record is missing an attribute required by a structural object class, an OBJECT_CLASS_VIOLATION will be raised, and so on. Of course, since all of these are subclasses of LDAPError, these numerous exceptions can all be caught in a try/except clause like this: >>> try:... l.add_s('uid=william,ou=users,dc=example,dc=com', attrs )... except ldap.LDAPError, e:... print e.message['info']... This will catch any of the LDAP exceptions, and display some of the error text, rather than showing the stack trace. Now we are ready to move on to the most complicated of writing operations: the LDAP modify operation. The Modify Operation Here we will look at the LDAP modify operation, which is used for modifying attributes – adding, replacing, or removing them from already-existing records. The OpenLDAP command line tool ldapmodify provides one way of performing this operation. In the Python-LDAP library, the modify() and modify_s() methods provide asynchronous and synchronous methods for performing modifications to the directory information tree. The signature of these methods is same as that of the add methods. There are two parameters: the DN and a list of modification tuples. The main difference is that the form of the tuples in this modification list is different than those in the add methods. A tuple in a modification list has three items: The modification type The attribute name A list of attribute values Modification type is one of three different constants defined in the ldap module: MOD_ADD: This is used to add an attribute value. If the attribute already exists (and the schema permits multiple values), the new value will be added, and the old value will remain. MOD_DELETE: The attribute value will be removed, if it exists. MOD_REPLACE: The given attribute values will replace all other values for that attribute name. In other words, all old values for the attribute will be deleted, and then this value will be added. For example, a simple list for adding a new givenName to an existing entry might look like this: mod_attrs = [( ldap.MOD_ADD, 'givenName', 'Francis' )] This list contains only one attribute to be modified. It will (if successful) add a new givenName attribute to the specified record. The modification can then be done with code like this: >>> mod_attrs = [( ldap.MOD_ADD, 'givenName', 'Francis' )]>>> l.modify_s('uid=francis,ou=users,dc=example,dc=com', mod_attrs)(103, [])>>> This will add the specified attribute value to the uid=francis record that we created above. As a result, dumping the LDIF record will show the newly added attribute: dn: uid=francis,ou=users,dc=example,dc=comcn: Francis BacongivenName: FrancisobjectClass: personobjectClass: organizationalPersonobjectClass: inetOrgPersonou: userssn: Baconuid: francisuserPassword: secret The highlighted line above shows the newly added attribute value. The modifyModList() function in the ldap.modlist module can help convert modification lists stored in dictionaries to the appropriate tuple-based format. What if Francis decided that he preferred to go by Frank? We could perform a slightly more sophisticated modification, changing his givenName to Frank, and adding a second CN value: >>> mod_attrs = [... ( ldap.MOD_REPLACE, 'givenName', 'Frank' ),... ( ldap.MOD_ADD, 'cn', 'Frank Bacon' )... ]>>> l.modify_s('uid=francis,ou=users,dc=example,dc=com', mod_attrs)(103, [])>>> Notice that our modification list now has two different modifications. First, it will replace givenName. Second, it will add a new cn attribute value. The result will be something like this: dn: uid=francis,ou=users,dc=example,dc=comcn: Francis Baconcn: Frank BacongivenName: FrankobjectClass: personobjectClass: organizationalPersonobjectClass: inetOrgPersonou: userssn: Baconuid: francisuserPassword: secret If we wanted to change the UID attribute, we would have to use the modrdn() or modrdn_s() method, since uid is used in the DN. If we try to change it with modify_s() or modify(), we will get a NAMING_VIOLATION exception. Finally, we can use the modify methods to remove attribute values: >>> mod_attrs = [ (ldap.MOD_DELETE, 'cn','Francis Bacon') ]>>> l.modify_s('uid=francis,ou=users,dc=example,dc=com', mod_attrs)(103, [])>>> This will remove only the attribute value Francis Bacon from the cn attribute. If no such value exists, a NO_SUCH_ATTRIBUTE exception will be raised. Otherwise, the value will be discarded. Note that some attributes are required by the record's object classes to be present in an entry. Attempting to delete the last value for such an attribute will result in an OBJECT_CLASS_EXCEPTION being raised. Removing All Attribute Values Sometimes it is necessary to remove all of the values for an attribute in a record, instead of just one specific value, as we did above. Let's look at an example. First, we add a few attribute values – two descriptions: >>> mod_attrs = [ ... (ldap.MOD_ADD, 'description', 'Author of New Organon'),... (ldap.MOD_ADD, 'description', 'British empiricist') ... ]>>> l.modify_s('uid=francis,ou=users,dc=example,dc=com', mod_attrs)(103, []) Now we have a record with two new descriptions. We can perform a very specific search to verify this. >>> l.search_s('uid=francis,ou=users,dc=example,dc=com', ... ldap.SCOPE_BASE, '(uid=francis)',['description'])[('uid=francis,ou=users,dc=example,dc=com', {'description': ['Author of New Organon', 'British empiricist']})] This search looks at just the uid=francis record, and shows just the description attributes. Now, how can we delete both of these attribute values without having to supply the exact attribute values for each? We can do this removal by creating a modification entry that uses None instead of a string for the final item in the attribute tuple: >>> mod_attrs = [( ldap.MOD_DELETE, 'description', None )]>>> l.modify_s('uid=francis,ou=users,dc=example,dc=com', mod_attrs)(103, [])>>> A simple search will verify that both description attribute values have been deleted: >>> l.search_s('uid=francis,ou=users,dc=example,dc=com', ... ldap.SCOPE_BASE, '(uid=francis)',['description'])[('uid=francis,ou=users,dc=example,dc=com', {})]>>> The server returned one entry – one with the DN for uid=francis – but since there were no description attribute values, the dictionary is empty.
Read more
  • 0
  • 0
  • 16824

article-image-roles-and-permissions-moodle-administration-part1
Packt
23 Oct 2009
1 min read
Save for later

Roles and Permissions in Moodle Administration: Part1

Packt
23 Oct 2009
1 min read
Lets get started. Moodle's PreDefined Roles Moodle comes with a number of predefined roles. These standard roles are suitable for some educational setups, but most institutions require modifications to the roles' system in order to tailor Moodle to their specific needs. Each role has permissions for a number of actions that can be carried out in Moodle. For example, an administrator and a course creator are able to create new courses, whereas all other roles are denied this right. Likewise, a teacher is allowed to moderate forums, whereas students are only allowed to contribute to them. Before we can actually do anything with roles, we need to understand the concept of contexts, which is dealt with next. Contexts Contexts are the areas in Moodle where roles can be assigned to users. A role can be assigned within different contexts. A user has a role in any given context, where a context can be a course, an activity module, a user, a block, or Moodle itself. Moodle comes with the following seven contexts that you will come across a lot in this article.
Read more
  • 0
  • 0
  • 3470
Modal Close icon
Modal Close icon