Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
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
article-image-securing-small-business-server-2008
Packt
24 Oct 2009
5 min read
Save for later

Securing the Small Business Server 2008

Packt
24 Oct 2009
5 min read
To do this, we are essentially completing the tasks in the home screen of the Windows SBS Console, which should look like the following screenshot. Assumptions I'm assuming that you understand the concepts of firewalls and ports; otherwise, you will struggle to safely configure your network. I'm also aware that OneCare, for servers, only provides an introductory offer for anti-malware and another product will be required; however, it is easier to describe the installation of one product rather than trying to answer for all products, so I'm using OneCare as a template. You will, however, need an anti-malware product that is server aware, or need to exclude server product locations such as the exchange data stores and other locations. Network security configuration There are a few areas where we can improve the security of the network. They are around the firewall, reducing the traffic that arrives at the SBS 2008 server, and the security certificate that is used to secure and identify the server communications. Configuring the firewall ports You will need the following ports configured on your firewall to direct traffic to SBS 2008: If you were using SBS 2003, then you can close down ports 444 and 4125, which might have previously been open. Loading a third-party security certificate SBS 2008 creates a security certificate to secure its communications. Certificates are only valuable if everybody seeing them trusts the system that issues the certificate. All computers that are part of the SBS 2008 network trust the SBS 2008 server, so trust is achieved in this way. For those that are not part of the SBS 2008 network, a special certificate must be loaded onto those machines so they will trust SBS 2008, else they will provide warnings to users about the integrity of the communication. There are organizations called Certificate Authorities who have established trust in the marketplace and most IT systems trust the certificates they issue. If you wish to have a more publically trusted certificate, then you will need to purchase one of these. One area where third-party certificates are often needed is when using mobile devices, to enable the loading of the SBS 2008 certificate onto the phones. Without the certificate on the phone, synchronization of Outlook information to the phone cannot take place. Importing a certificate If you already have a certificate or have purchased one and have been sent a file containing the certificate including the private keys, then you should follow this process. There are two steps to follow: Importing the certificate into the Local Computer Certificate store Assigning the certificate using the SBS Console Importing the certificate Start Windows SBS Console (Advanced Mode) from the Start menu and click on the Network tab and then the connectivity button. As this is the advanced console, you will see extra tasks available on the righthand side. Click on the Manage certificates task—if this is not present, check you are running the Advanced Mode console: it will say so in the title bar. This will run a management console with the certificates for your computer made visible. Expand the Personal tree and right-click on Certificates and select Import from the All Tasks menu item. Click Next to pass through the welcome screen for the Certificate Import Wizard and then click on the Browse button to locate the certificate. Then, click on Next to continue. You will now be required to enter your Password to enable access to the key. I would put a check mark in the two remaining check boxes to Mark the key as exportable to enable you to export the certificate should you need to in the future and include the extended properties. Then, click on Next. You will be required to confirm the location, which should be Personal and again click on Next. If it is not set to Personal, click on the Browse button and change the Certification store to Personal. Now click on Finish to complete the process and you will see a message stating that The import was successful. Close the Certificates Management console. Assigning the certificate In the Windows SBS Console, click the task Add a trusted certificate to start the process. Click on Next to skip past the introduction. If you have assigned a certificate before, you will be told that A valid trusted certificate already exists and you have the choice of renewing your existing certificate or replacing it. Select I want to replace the existing certificate with a new one and click on Next. If you have not added a trusted certificate before, then you will not see this screen. On the Get the certificate page, select the option to use a certificate already installed on the server and click on Next. The certificate that you installed will show in the list with a Type of Trusted, while the certificates issued by SBS 2008 will show as Self-issued. Select your Trusted certificate and click on Next. Click on Next to start the process and then Finish to exit the wizard.
Read more
  • 0
  • 0
  • 6484

article-image-service-versioning-soa
Packt
24 Oct 2009
15 min read
Save for later

Service Versioning in SOA

Packt
24 Oct 2009
15 min read
Making a Change For the next few months, the Center of Excellence paid off. Projects were identifying services early in the lifecycle. Those same projects were successfully identifying other potential consumers of these new services. Implementation technologies were being chosen correctly and interface design was being properly done. Most importantly, everyone felt the SOA effort was on track. By this time, it had been almost two years since Spencer's team developed the Customer Information Service for the auto insurance and home insurance divisions. While these two groups were very happy with the results, no additional teams had leveraged it. Outside of the annuity project, this wasn't a case of projects going in another direction; it was more due to lack of opportunities. That was about to change. Spencer was eating lunch in the cafeteria when Ramesh walked up. "Mind if I join you, Spencer?" "Hey Ramesh, it's been quite some time. Go ahead and pull up a chair." "Do you remember two years ago you tried to convince Ryan to use your Customer Information Service?" "I sure do. I didn't want to show my face in the annuity area for about a month after that. He really wasn't very receptive to the idea." "Well, I have some good news and some better news for you. The good news is that about six months later, Ryan decided to leave Advasco. The better news is that we've now got a major initiative to revamp a number of our systems in the annuity department. I'd like to take advantage of the Customer Information Service as part of that effort." "That's good news Ramesh. I didn't harbor any resentment towards Ryan, but I'm certainly happy about having another potential consumer for the Customer Information Service. I'll put you in touch with the service manager for it." "Thanks Spencer. That would be great. We're just getting started on our architecture, so the timing is perfect." "Let me know if you run into any problems. I'm still part of the SOA Center of Excellence, so it's still my job to make sure it goes well!" Spencer put Ramesh in contact with the service manager for the Customer Information Service, Maria. Maria had recently transferred over after her work on the account maintenance effort, and now had responsibilities for the Customer Information Service. In the meeting with Ramesh, she brought her technical lead, Craig, with her "Spencer told me that you're interested in utilizing the Customer Information Service in some of the new systems you're building in the annuity department, Ramesh." "That's right. We're rewriting a number of our systems, and based on what I remembered from Spencer two years ago, I thought we might be able to leverage the service." "Great, I'd be happy to help you out. This is Craig, the technical lead who covers the Customer Information Service. He's here if you've got any technical questions. Have you had a chance to review the information available in the service repository?" "I have. I reviewed the service interface, and while it certainly looks like there's enough there to warrant using the service rather than building our own, there's also a number of additional things that we'll need." Craig responded, "What kind of changes are you looking for? Are there new operations that you need that are specific to the annuity area?" Ramesh said, "There are two or three operations that we'd like to see, but most of the changes are actually in the message schemas for the existing operations. There are some additional attributes that we need, and some of the relationships between the attributes are different in our representation." For the rest of the meeting, Ramesh and Craig went through the changes that Ramesh wanted to be made to accommodate his needs. In the end, it was clear that some changes to the existing schemas would have to be made. Maria asked, "We're going to need to go back and look over these changes, along with the integration approach for your existing database. What does the schedule for your efforts currently look like?" Ramesh replied, "We're still in the initial stages of planning, which is why I wanted to make sure I talked to you now. Right now, the project sponsors would like to have something within six months, but they also know that nine months is far more likely. Since I have some flexibility in my schedule, why don't you take a week to look into the effort required for the changes, and let's work out the schedule then. Does that work for you?" "That works for me. We'll get back to you next week with what we think it will take to implement the changes." On the way back to their desks, Craig commented to Maria, "You know, while I don't have any concerns about getting the work done for Ramesh, I do have some concerns on how these changes are going to impact our existing consumers. Some of these changes are going to break the existing interfaces." Maria said, "That is a concern. I know that there aren't any resources available to do any work on the home insurance side of things. Any suggestions on how we should handle this?" Craig said, "Well, we definitely should make the existing consumers aware that a change is going to be made and at least get a clear idea of what the impact will be. If you can take care of that, I can take this to Spencer and the SOA Center of Excellence, and see what suggestions they have." "That sounds like a good plan to me," replied Maria Over the next week, the Customer Information Service team did the analysis required to estimate how long the changes would take to implement. Maria used the communication features of the service registry/repository to push out a message to the existing consumers about the pending change, and as she suspected, the biggest problem was going to be the home insurance system. Due to other priorities, the earliest they could even begin to make changes to their consumer would be nine months from now, potentially three months after the service needed to go live. Craig met with Spencer and explained the problem to him. Spencer agreed to facilitate a decision-making session to explore the different options. Representatives from all of the existing consumers were there, along with Ramesh, Craig, and Maria Spencer started the meeting, "I'm sure all of you saw the notification from Maria last week that some changes are necessary to the Customer Information Service in order to support its usage by the annuity department. The problem that we face is that these changes will break the existing consumers of the service, and not all of you can make the changes to your systems in the currently proposed timeframe. Let's start out by listing all possible options, regardless of whether we all presently agree or disagree on their viability." Craig started out, "Well, if we're listing all possible options, the first one is toupdate the service, and then get whatever push we need from management to get resources allocated to the consuming systems so they can make the changes in the time required." Maria replied, "Come on Craig, you know that we can't just pull resources off projects that easily." Jason, from the auto insurance department, added, "Aren't all of these changes a result of the annuity department? Why can't they just include modifying our applications within their project scope? They already have resources allocated to their project." Paul, from the home insurance department, replied, "Do you really want some developers that have never seen your application before mucking around in your code? I know I don't." Spencer said, "Let's remember, we're listing all options, regardless of whether we all know that the option won't fly. We want to make sure we've explored all of the options. I'm going to just leave this as one option, since we still wind up with the same result, regardless of where the resources come from. I'll capture the concerns about the option." Paul, from the home insurance group, added, "Okay, here's another option. Why don't we leave the existing service in place, and simply have the annuity project write a new service that just they use. Then, none of us using the existing service would be impacted." Craig replied, "That's true, but isn't that going against everything we're trying to do with SOA? I thought we were trying to avoid redundant implementations of the same capability." Spencer replied, "Duly noted, Craig. Just as with the last option, let's keep it on the board, and I'll make sure that your concerns are captured. Paul, that option actually triggered another one in my mind. In addition to having Maria's team write the new service for the annuity system, why couldn't they also keep the existing version of the service available in production for the rest of you? You can then migrate as your schedules allow." Paul and Jason both replied in tandem, "That would work for us!" Maria jumped into the conversation, "While I'm sure it would, that sets a very dangerous precedent for my team. How many versions of the service are we going to have to maintain? While it's a little bit better when all the implementations are owned by one team, we still have multiple implementations." Jason then asked, "Isn't there a way to make the new service backwards compatible with the messages associated with the old service? That way, Maria's teamwould only have one implementation, but we could each continue to use our existing interface." Spencer replied, "That's a very good question Jason. While we all agree that the service interface needs to change to support the annuity department's requirements, I don't know that any of us have thought about whether we can easily transform messages associated with the previous version to messages that will work with the new version, and vice versa. Craig, you're the one most familiar with the new proposed schemas. Do you think we could leverage XSLT to apply transformations for backward compatibility?" "Yes, I think it's possible. The only concern I have is what impact this will have on the service implementation. Working with XSLT within Java code isn't the easiest thing to do, and as we make future modifications, that's just going to get uglier and uglier." Spencer said, "There's another option for that. A year ago, we put some XML appliances in place for security purposes. I know they have XSLT capabilities and they're already in the request path." Craig replied, "Of all the options, I think that one would work out the best. I really don't like the idea of maintaining multiple versions of the service, and having to maintain all of that XSLT code within the service is only slightly better. Allowing the annuity group to write their own goes against everything we're trying to do with SOA." Spencer said, "Well, we know where Craig stands. Are there any other options that we should look into? No? Well, what does everyone think?" Paul was first, "We know that we're not going to find resources to make the changes in all of the consumers at the same time, so that option is out. Likewise, it doesn't make sense for Ramesh's team to write their own service given our SOA goals, so that one is out, too. As for whether Maria's team maintains two versions of the service or utilizes some transformations somewhere, it really doesn't matter to me. From my perspective, both options give me the freedom to migrate at the time that works best for me." Jason immediately added, "I agree with everything Paul just said." Ramesh then offered his opinion, "Well, I certainly know that I don't want to give up any of my developers to work on Jason's and Paul's systems. We need every developer we can get right now. As for writing our own service, we've already been down that path two years ago, and now we're obviously changing the system again. If we had migrated to the service earlier, it would be one less thing that we had to touch as part of these changes. As long as Maria's team delivers my service on time for my projects, it doesn't matter to me what Maria's team chooses to do on their side." Spencer replied, "Well Maria, it looks like everyone else thinks that we need a solution that will allow all of the consumers to continue to use their existing interfaces or the new one, but the details of how that happens is completely up to you and Craig." Maria said, "Let's not jump to conclusions yet. If I'm going to maintain multiple versions, I need some kind of guarantee that the existing consumers will eventually migrate to the new version. If my team allows continuous use of the old interface for 12 months from the time the new interface goes live, would that be an adequate time to complete whatever modifications are necessary?" Jason and Paul thought about it and decided that this was reasonable. For the past three years, they'd averaged an update every nine months. Maria said, "I'll make sure to remind you, early and often, that the old version and its associated interfaces are going to be decommissioned. In the meantime, I'd like to first get the new version built. I'm going to need to keep both versions around initially just to compare messages. Ramesh's team can begin using the new service, and…" As she was talking, she stopped mid-sentence. Spencer said, "Is there a problem, Maria?" She replied, "Well, I was just thinking, how are we going to avoid having two URL's out there? The existing consumers are using a URL that points to the XML appliances, right? We want to apply transformations to that path. What URL will Ramesh's team use? We don't want to try to apply transformations to their requests." Spencer said, "Fortunately, I don't think we'll need to do that. We'll need to talk to the team that operates the appliances to be sure, but I'm pretty sure that the appliances can apply processing based upon incoming attributes on the message. As long as we can determine which requests came from which consumer based on the message content, we should be able to control when transformations happen, while having all the existing consumers using a single URL. We'll obviously need multiple URLs behind the intermediary, but that will be hidden from the consumers." Maria replied, "Okay, that eases some of my fears. Just make sure you find out quickly whether the appliances can handle it or not. Until we find out, can we set up a simple routing rule so that requests from the annuity group go to the new service, while the old ones stay where they are? That way, Ramesh can use the new service as soon as it is available, and Craig and his team can start working on the transformations for backward compatibility. I'd like to wait and see how that work goes before deciding whether to leave both versions out there for 12 months or to leverage the intermediary. We've never used that functionality before, and I don't want to take a chance on impacting Ramesh's schedule in case we run into difficulty. By keeping both services available in production at first, we can eliminate any dependency between the decommissioning of the old service and Ramesh's schedule." Craig added, "From my point of view, that shouldn't be a problem. I can treat the new version as if it were a completely new service, as long as the intermediary shields the consumers from that change. I will need to check how we can manage both versions at the source code level, though." Maria responded, "Good points, Craig. Taking all of this into account, I think this approach poses the least risk overall." Spencer said, "Then we're all in agreement, right? Maria's team will build a new version of the service according to the new interface, and the old interface will be available for 12 months from the time the new service is deployed. Initially, both versions will be available in production, but Maria can decommission the old service before 12 months are up, so long as the new version can be made backwards compatible via XSLT transformations. Maria will notify all consumers prior to decommissioning the old service, since regression testing will be required to ensure that backward compatibility has been maintained. She will also notify all consumers as we get closer to the 12 month cutoff when the older interface will no longer be supported." Everyone in the meeting agreed with this approach, and the teams went off and made it happen. Craig's team investigated the best way to apply the transformations, testing them using the latest Java libraries, as well as the XML appliances that Advasco had recently installed. They found that the XML appliances performed very well, and kept the programming model of the service very clean. While the Java libraries performed satisfactorily, the resulting programming model was not as clean as the team desired. With the use of the routing rules in the appliance, they were able to remove the older version of the service from production, while still supporting the older messages for the full 12 months as promised.
Read more
  • 0
  • 0
  • 1453

article-image-dynamic-theming-drupal-6-part-2
Packt
24 Oct 2009
8 min read
Save for later

Dynamic Theming in Drupal 6 - Part 2

Packt
24 Oct 2009
8 min read
Creating Dynamic CSS Styling In addition to creating dynamic templates, the Drupal system also enables you to apply CSS dynamically. Drupal creates unique identifiers for various elements of the system and you can use those identifiers to create specific CSS selectors. As a result, you can provide styling that responds to the presence (or absence) of specific conditions on any given page. Two of the most common uses of this technique are covered below: The creation of node-specific styles and the use of $body_classes. Using Dynamic Selectors for Nodes The system generates a unique ID for each node on the website. We can use that unique ID to activate a unique selector by applying this nomenclature for the selector: #node-[nid] {} For example, assume you wish to add a border to the node with the ID of 2. Simply create a new div in style.css with the name: #node-2 {border: 1px solid #336600} Changing the Body Class Based on body_classes One of the most useful dynamic styling tools introduced in Drupal 6 is the implementation of $body_classes. This variable is intended specifically as an aid to dynamic CSS styling. It allows for the easy creation of CSS selectors that are responsive to the layout of the page. This technique is typically used to control the styling where there may be one, two or three columns displayed, depending on the page and the content. Prior to Drupal 6, $layout was used to detect the page layout, that is, one, two or three columns. While $layout can technically still be used, the better practice is to use $body_classes. Implementing $body_classes is a simple matter; just add $body_classes to the body tag of your page.tpl.php file—the Drupal system will do the rest. Once the body tag is altered to include this variable, the class associated with the body tag will change automatically in response to the conditions on the page at that time. Now, all you have to do is create the CSS selectors that you wish to see applied in the various situations. Let's step through this with a quick example. Open up your page.tpl.php file and modify the body tag as follows: <body class="<?php print $body_classes; ?>"> This will now automatically create a class for the page based on the conditions on the page. The chart below shows the options this presents: Condition Class Available no sidebars .no-sidebar one sidebar .one-sidebar left sidebar visible .sidebar-left right sidebar visible .sidebar-right two sidebars .two-sidebars front page .front not front page .not-front logged in .logged-in not logged in .not-logged-in page visible .page-[page type               node visible .node-type-[name of type]       $body_classes provides the key to easily creating a theme that includes collapsible sidebars. To set up this functionality, modify the page.tpl.php file to include $body_classes. Now, go to the style.css file and create the following selectors: .one-sidebar {}.sidebar-left {}.sidebar-right {}.no-sidebar {}.two-sidebars {} The final step is to create the styling for each of the selectors above (as you see fit). When the site is viewed, the system-generated value of $body_classes will determine which selector is applied. You can now specify, through the selectors above, exactly how the page appears—whether the columns collapse, the resulting widths of the remaining columns, and so on , and so on. Working with Template Variables As we have seen, above, Drupal produces variables that can be used to enhance the functionality of themes. Typically, a theme-related function returns values reflecting the state of the page on the screen. A function may indicate, for example, whether the page is the front page of the site, or whether there are one, two, or three active columns (for example, the variable $body_classes). Tapping into this information is a convenient way for a theme developer to style a site dynamically. The default Drupal variables cover the most common (and essential) functions, including creating unique identifiers for items. Some of the Drupal variables are unique to particular templates; others are common to all. In addition to the default variables, you can also define your own variables. Using the function theme_preprocess(), you can either set new variables, or unset existing ones that you do not want to use. In Drupal 6, preprocess functions have made working with variables easier and cleaner. By using the preprocessor, you can set up variables within your theme that can be accessed by any of your templates. The code for the preprocess function is added to your template.php file, thereby keeping the actual template files (the .tpl.php files) free of unnecessary clutter. Note that the preprocess functions only apply to theming hooks implemented as templates; plain theme functions do not interact with the preprocessors. In Drupal 5 and below, the function _phptemplate_variables served the same purpose as the preprocess function. For a list of the expected preprocess functions and their order of precedence, see http://drupal.org/node/223430 Typically, if you wish to implement a preprocessor applicable to your theme, you will use one of the following:   Name of preprocessor Application [engineName]_preprocess This namespace should be used for your base theme. Should be named after the theme engine used by the theme. Will apply to all hooks. [engineName]_preprocess_ [hookname] Should be used for your base theme. Also named after the theme engine applicable to the theme but note that it is specific to a single hook. [themeName]_preprocess This namespace should be used for subthemes. Will apply to all hooks. [themeName]_preprocess_ [hookname] Should be used for subthemes. Note that it is specific to a single hook. Let's look first at intercepting and overriding the default variables and then at creating your own variables. Intercepting and Overriding Variables You can intercept and override the system's existing variables. Intercepting a variable is no different in practice from intercepting a themable function: you simply restate it in the template.php file and make your modifications there, leaving the original code in the core intact. To intercept an existing variable and override it with your new variable, you need to use the function _phptemplate_preprocess(). Add this to your template.php file according to the following syntax: <?phpfunction phptemplate_preprocess(&$vars) {$vars['name'] = add your code here...;}?> Note that nothing should be returned from these functions. The variables have to be passed by reference, as indicated by the ampersand before variables, e.g., &$vars. Let's take a very basic example and apply this. Let's override $title inpage.tpl.php. To accomplish this task, add the following code to the template.php file: <?php function phptemplate_preprocess(&$vars) { $vars['title'] = 'override title';}?> Remember to clear your theme registry! With this change made and the file saved to your theme, the string override title will appear, substituted for the original $title value. Making New Variables Available The preprocess function also allows you to define additional variables in your theme. To create a new variable, you must declare the function in the template.php file. In order for your theme to have its preprocessors recognized, the template associated with the hook must exist inside the theme. If the template does not exist in your theme, copy one and place it in the theme directory. The syntax is the same as that just used for intercepting and overriding a variable, as seen above. The ability to add new variables to the system is a powerful tool and gives you the ability to add more complex logic to your theme. Summary In this two part article we covered the basics needed to make your Drupal theme responsive to the contents and the users. By applying the techniques discussed here, you can control the theming of pages based on content, state of the page or the users viewing them. Taking the principles one step further, you can also make the theming of elements within a page conditional. The ability to control the templates used and the styling of the page and its elements is what we call dynamic theming. We covered not only the basic ideas behind dynamic theming, but also the techniques needed to implement this powerful tool. Among the items discussed at length were the use of suggestions to control template display, and the implementation of $body_classes. Also covered in this article, was the use of the preprocess function to work with variables inside your theme
Read more
  • 0
  • 0
  • 1770

article-image-vbnet-application-sql-anywhere-10-database-part-2
Packt
24 Oct 2009
3 min read
Save for later

VB.NET Application with SQL Anywhere 10 database: Part 2

Packt
24 Oct 2009
3 min read
[Read the first part of this article here] Now you can click on the Preview Data… hyperlink which opens up the Preview Data window as shown in Figure 19. The Select an object to preview field gets populated automatically to run the getData () method. When you click on the Preview button, the grey area is populated by a table showing the retrieved rows of data from the Customers table as shown in Figure 19. Figure 19 Click on the Close button in the above window. In the various tasks of the DataGridView many options are chosen by default. You may also check reordering of the column by placing a check mark in the Edit Column Reordering in Figure 18 which opens Edit Columns window as shown in Figure 20, another useful control to manipulate the columns so that the columns you want to see are the first few columns. Figure 20 You may want to edit the columns and change some of the items such as reordering of the columns, column name, column width, etc. All this can be done from this screen. For this tutorial only the columns width was changed. A label was added and its text was changed to, "Demo 10 Database Customers" as shown in Figure 21. Figure 21     Build the project from the main menu item, Build. Now when the program is run by clicking the Debug --> Start without debugging, or by pressing Ctrl+F5, the program runs and Form1 is displayed as shown in Figure 22. Figure 22 Figure 23 shows the properties of the dataset DsAny that is created when the data source was created. Figure 23   The schema of the above dataset is shown in Figure 24. This gets added to the project files in the Solution Explorer. Figure 24   Using the smart tasks on the CustomerBindingSource you can carry out few of the indicated tasks shown in Figure 25. Figure 25   The properties of the CustomerBindingSource are shown in Figure 26. Figure 26 The CustomerTableAdapter directly connects to the database and it has its own properties window as shown in Figure 27. You will be able to edit queries in the dataset designer, add query, etc using the hyperlinks at the bottom of the properties window. Figure 27 Alternatively you will be able to carry out similar tasks from the smart tasks on the CustomerTableAdapter component in the component tray as shown in Figure 28. In Microsoft applications, you have more than one way of carrying out a task. Figure 28 The Object Browser shown in Figure 29 for this project shows the various data related classes that are used in the application working behind scenes as not a single line of code was explicitly used for this form to display the data. Figure 29  
Read more
  • 0
  • 0
  • 3469

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-minilang-and-ofbiz
Packt
23 Oct 2009
11 min read
Save for later

Minilang and OFBiz

Packt
23 Oct 2009
11 min read
What is Minilang? The syntax of Minilang is simply well formed XML. Developers write XML that obeys a defined schema, this XML is then parsed by the framework and commands are executed accordingly. It is similar in concept to the Gang of Four Interpreter Pattern. We can therefore consider Minilang's XML elements to be "commands". Minilang is usually written in a simple method's XML file, which is specified at the top of the document like this: xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/ simple-methods.xsd"> Although Minilang's primary use is to code services and events, concepts from Minilang are also used to prepare data for screen widgets. Much of the simplicity of Minilang arises from the fact that variables are magically there for us to use. They do not have to be explicitly obtained, they are placed in the environment and we can take them as we wish. Should we wish to create a Map, we just use it, the framework will take care of its creation. For example: <set field="tempMap.fieldOne" from-field="parameters.fieldOne"/> will set the value of the fieldOne parameter to tempMap. If tempMap has already been used and is available, this will be added. If not, the Map will be created and the value added to the key fieldOne. Tools to Code XML Minilang is coded in XML and before it can be successfully parsed by the framework's XML parser, this XML must be well formed. Trying to code Minilang in a plain text editor like Notepad is not a wise move. Precious time can be wasted trying to discover a simple mistake such as a missing closing tag or a misspelled element. For this reason, before attempting to code Minilang services, make sure that you have installed some kind of XML editor and preferably one with an auto-complete feature. The latest versions of Eclipse come packaged with one and XML files are automatically associated to use this editor. Alternatively there are many editors available to download of varying functionality and price. For example XML Buddy (http://www.xmlbuddy.com), oXygen XML Editor (http://www.oxygenxml.com), or the heavyweight Altova XMLSpy (http://www.altova.com) Defining a Simple Service Minilang services are referred to as "simple" services. They are defined and invoked in the same way as a Java service. They can be invoked by the control servlet from the controller.xml file or from code in the same way as a Java service. In the following example we will write a simple service that removes Planet Reviews from the database by deleting the records. First open the file ${component:learning}widgetLearningForms.xml and find the PlanetReviews Form Widget. This widget displays a list of all reviews that are in the database. Inside this Form Widget, immediately under the update field element add: <field name="delete"><hyperlink target="RemovePlanetReview?reviewId=${reviewId}" description="Delete"/></field> Our list will now also include another column showing us a hyperlink we can click, although clicking it now will cause an error. We have not added the request-map to handle this request in the controller.xml. It will be added a little later. Defining the Simple Service In the file ${component:learning}servicedefservices.xml add a new service definition: <service name="learningRemovePlanetReview" engine="simple" location="org/ofbiz/learning/learning/LearningServices.xml" invoke="removePlanetReview"> <description>Service to remove a planet review</description> <attribute name="reviewId" type="String" mode="IN" optional="false"/> </service> Note that the engine type is simple. It is a common practice to group service definitions into their own XML file according to behavior. For instance, we may see that all services to do with Order Returns are in a file called services_returns.xml. So long as we add the <service-resource> element to the parent component's ofbiz-component.xml file and let the system know that this service definition file needs to be loaded, we can structure our service definitions sensibly and avoid huge definition files. It is not a common practice, however, to group service definitions by type. The type is abstracted from the rest of the system. When the service is invoked, the invoker doesn't care what type of service it is. It could be Java, it could be a simple service, it doesn't matter. All that matters is that the correct parameters are passed into the service and the correct parameters are passed out. For this reason, simple service definitions are found in the same XML files as Java service definitions. Writing the Simple Method Simple Method XML files belong in the component's script folder. In the root of ${component:learning} create the nested directory structure scriptorgofbizlearninglearning and in the final directory create a new file called LearningServices.xml. Before we add anything to this file we must make sure that the script directory is on the classpath. Open the file ${component:learning}ofbiz-component.xml and if it is not already there add <classpath type="dir" location="script"/> immediately underneath the other classpath elements. The location specified in the service definition can now be resolved. In our newly created file LearningServices.xml add the following code: <simple-methods xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/ simple-methods.xsd"> <simple-method method-name="removePlantetReview" short-description="Delete a Planet Review"> <entity-one entity-name="PlanetReview" value-name="lookedUpValue"/> <remove-value value-name="lookedUpValue"/> </simple-method> </simple-methods> Finally all that is left is to add the request-map to the controller.xml: <request-map uri="RemovePlanetReview"> <security auth="true" https="true"/> <event type="service" invoke="learningRemovePlanetReview"/> <response name="success" type="view" value="ListPlanetReviews"/> <response name="error" type="view" value="ListPlanetReviews"/> </request-map> Since we have added a new service definition OFBiz must be restarted. A compilation is not needed. Restart and fire an http request ListPlanetReviews to webapp learning: Selecting Delete will delete this PlanetReview record from the database. Let's take a closer look at the line of code in the simple service that performs the lookup of the record that is to be deleted. <entity-one entity-name="PlanetReview" value-name="lookedUpValue"/> This command will perform a lookup on the PlanetReview entity. Since the command is <entity-one> the lookup criteria must be the primary key. This code is equivalent in Java to: GenericValue lookedUpValue = delegator.findByPrimaryKey ("PlanetReview", UtilMisc.toMap("reviewId", reviewId)); Already we can see that Minilang is less complicated. And this is before we take into account that the Java code above is greatly simplified, ignoring the fact that the delegator had to be taken from the DispatchContext, the reviewId had to be explicitly taken from the context Map and the method call had to be wrapped in a try/catch block. In Minilang, when there is a look up like this, the context is checked for a parameter with the same name as the primary key for this field, as specified in the entity definition for PlanetReview. If there is one, and we know there is since we have declared a compulsory parameter reviewId in the service definition, then the framework will automatically take it from the context. We do not need to do anything else. Simple Events We can call Minilang events, in the same way that we called Java events from the controller.xml. Just as Minilang services are referred to as simple services, the event handler for Minilang events is called "simple". Tell the control servlet how to handle simple events by adding a new <handler> element to the learning component's controller.xml file, immediately under the other <handler> elements: <handler name="simple" type="request" class="org.ofbiz.webapp.event.SimpleEventHandler"/> A common reason for calling simple events would be to perform the preparation and validation on a set of parameters that are passed in from an XHTML form. Don't forget that when an event is called in this way, the HttpServletRequest object is passed in! In the case of the Java events, it is passed in as a parameter. For simple events, it is added to the context, but is nonetheless still available for us to take things from, or add things onto. In the same location as our LearningServices.xml file (${component:learning} scriptorgofbizlearninglearning) create a new file called LearningEvents.xml. To this file add one <simple-method> element inside a <simple-methods> tag: <simple-methods xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/ simple-methods.xsd"> <simple-method method-name="simpleEventTest" short-description="Testing a simple Event"> <log level="info" message="Called the Event: simpleEventTest"/> </simple-method> </simple-methods> Finally, we need to add a request-map to the controller from where this event will be invoked: <request-map uri="SimpleEventTest"> <security auth=true»https=true/> <event type=»simple»path=»org/ofbiz/learning/learning/ LearningEvents.xml»invoke=»simpleEventTest»/> <response name=»success»type=»view»value=»SimplestScreen»/> <response name=»error»type=»view»value=»SimplestScreen»/> </request-map> Notice our simple method doesn't actually do anything other than leave a message in the logs. It is with these messages that we can debug through Minilang. Validating and Converting Fields We have now met the Simple Methods Mini-Language, which is responsible for general processing to perform simple and repetitive tasks as services or events. Validation and conversion of parameters are dealt with by another type of Minilang—the Simple Map Processor. The Simple Map Processor takes values from the context Map and moves them into another Map converting them and performing validation checks en-route. Generally, Simple Map Processors will prepare the parameters passed into a simple event from an HTML form or query string. As such, the input parameters will usually be of type String. Other object types can be validated or converted using the Simple Map Processor including: BigDecimals, Doubles, Floats, Longs, Integers, Dates, Times, java.sql.Timestamps, and Booleans. The Simple Map Processors are, like simple methods, coded in XML and they adhere to the same schema (simple-methods.xsd). Open this file up again and search for The Simple Map Processor Section. The naming convention for XML files containing Simple Map Processors is to end the name of the file with MapProcs.xml (For example, LearningMapProcs.xml) and they reside in the same directory as the Simple Services and Events. One of the best examples of validation and conversion already existing in the code is to be found in the PaymentMapProcs.xml file in ${component:accounting}scriptorgofbizaccountingpayment. Open this file and find the simple-map-processor named createCreditCard. Here we can see that immediately, the field expireDate is created from the two parameters expMonth and expYear with a "/" placed in between (example, 09/2012): <make-in-string field="expireDate"> <in-field field="expMonth"/> <constant>/</constant> <in-field field="expYear"/> </make-in-string> Towards the end of the <simple-map-processor> this expireDate field is then copied into the returning Map and validated using isDateAfterToday. If the expiration date is not after today, then the card has expired and instead, a fail-message is returned. <process field="expireDate"> <copy/> <validate-method method="isDateAfterToday"> <fail-message message="The expiration date is before today"/> </validate-method> </process> The <validate-method> element uses a method called isDateAfterToday. This method is in fact a Java static method found in the class org.ofbiz.base.util.UtilValidate. We have already been using one of the OFBiz utility classes, UtilMisc, namely the toMap function, to create for us Maps from key-value pairs passed in as parameters. OFBiz provides a huge number of incredibly useful utility methods, ranging from validation, date preparation, and caching tools to String encryption and more. The framework will automatically allow Minilang access to this class. By adding a bespoke validation method into this class and recompiling, you will be able to call it from the <validate-method> in Minilang, from anywhere in your application.
Read more
  • 0
  • 0
  • 2371
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-windows-presentation-foundation-project-basics-working
Packt
23 Oct 2009
7 min read
Save for later

Windows Presentation Foundation Project - Basics of Working

Packt
23 Oct 2009
7 min read
Introduction WPF, an acronym for Windows Presentation Foundation is a subsystem of class libraries for WinFX and it enables the user to get a richer experience bringing together UI, Documents, media etc. A XAML (Extensible Application Markup Language) file which is at the heart of a WPF project can be created in several ways that includes the Notepad text editor, the Expression Blend which requires another download from Microsoft, but may not provide a easy to use XAML file to use in VS, and the Visual Studio editions except the express edition. XAML is presently specific to windows platform and is a XML formatting language and not an application programming interface. I will be mostly showing how to get some hands-on experience with a WPF project using the Visual Studio 2005 interface and the template files that you may access with the Windows SDK installed. Creating a WPF Project From File | New | Project click open the New Project window as shown in the next figure. Click on Visual Basic and expand its contents. Under .NET 3.0 FrameWork (It is assumed that you have installed NET 3.0 Framework) choose the Windows Application (WPF). Now highlight the Windows Application (WPF) and change the name of the application to some name of your choice. For this article it is changed to AppWPF. Click on the OK button after typing a name of your choice. This creates the necessary file/folders for the application as shown in the next figure. There are two XAML files created in the project. The App.xaml and the Windows1.xaml file. Delete the Windows1.xaml and add a new item as shown with the name BasicControls.xaml. With this new item added you may need to change the App.xaml file as shown below. <Application x_Class="App" StartupUri="BasicControls.xaml"> <Application.Resources> </Application.Resources> </Application> The StartupUri has been changed from the original Windows1.xaml to BasicControls.xaml. With this change made you can now display the BasicControls.xaml file together with its design as shown in the next figure. This represents a 300 X 300 window which can be used as a container for other controls. You also notice the reference to the namespaces that are required and the XML syntax with the attribute of the project for the window. Placing Controls on the Window Placing Controls automatically creates XAML code. Placing controls on this window is as easy as dragging from the Tools and dropping on to this window. The next picture shows a button and a textbox dragged and dropped onto this window. The necessary code for these controls gets automatically added as the controls are placed. After the two controls are added, the xaml file gets changed as shown. The Button and Textbox properties are the defaults which may be modified as will be seen later in the article. <Window x_Class="BasicControls" Title="AppWPF" Height="300" Width="300" > <Grid> <Button Height="23" Margin="94,0,123,39" Name="Button1" VerticalAlignment="Bottom">Button</Button> <TextBox HorizontalAlignment="Left" Margin="43, 126, 0,115" Name="TextBox1" Width="100"></TextBox> </Grid> </Window> Adding code automatically updates the window design. Inserting a declarative code into the BasicControls.xaml file will automatically add the control defined by that code to the design window. Add this code to the xaml file after as shown in the next paragraph. As soon as you type "<", the intellisense gets fired up and you will see a drop-down list of items that you can insert as shown in the next figure. Now you click on the Textbox (or whatever else you wish to place). This adds to the xaml file. Now to the opening tag of the textbox, you add a name attribute and call it TextBox2. Intellisense is also used in adding attributes as you will get a context sensitive listing of attributes for the chosen control. Also add other attributes such as width, height, alignment etc. With the code added as shown in the next paragraph you will see that the design pane has a new textbox as shown in the next figure.   <Textbox Name="TextBox2" Height="20" Margin="89.5,96.5,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="50"></TextBox*gt; The property window for the TextBox2 shown can also be used to make changes. You can also move, or adjust the dimensions of the controls using the mouse. The various controls provide a very rich interface for the designer in manipulating the controls. Event Handling All 'Hello World' programs used a button click to demonstrate the workings of the code or how the events were handled. In this tutorial also you will demonstrate the click event along the same lines. In the Solution Explorer only a few items are seen but there are lot more files in the project. Click on the middle toolbar just above the project as shown in the next figure. This will allow you to see all the files / folders in the project displayed (every folder expanded out) as shown. This is vastly different from a legacy windows project. The references to the Presentation Foundation are all in the three references, PresentationCore, PresentationDesignDeveloper and PresentationDesignFramework. In order to appreciate the rich designer support you have to go to the ,Object Browser and look at the references. For example just the PresentationCore has the following namespaces shown in the next figure. The BasicControls.xaml file also has the code behind file, BasicControls.xaml.vb, as shown in the next figure. In the code page, the drop-down control displaying BasicControls presently has all the objects on this window listed in its menu. You can find the Button as well. With the button chosen you can use the second drop-down to access all the events of the Button in the second drop-down (presently showing Declarations). In this manner the button click event was chosen from the second drop-down. Here the Button1_Click has been set to display "Click is registered" in Textbox1 when the button is clicked. You can find the reference to this in the Object Browser as shown in the next figure. Object Browser is an extremely valuable resource that you should seek out to understand the underlying logic, the arguments of a function call, etc. When you build and execute the program and click on the button this is what you will see displayed. The top part is the design window and the bottom is the window when clicked. At this point you might be wondering how to improve the look and feel. Indeed the form looks drab since none of the properties have been used except for the most basic. The next figure shows how you may change the appearance by inserting the property attributes directly into the XMAL file. You will be better off using the intellisense rather than trying to guess the property based on your previous 'Windows' experience as shown in the next figure. You may also add attributes from the property window of the object which you can view when the object is highlighted (or clicked) in the design pane. The variety of attributes is just too many and when in doubt you will be able to drill down to the one you want to use in the Object Browser. The next code listing shows a few more attributes added to the Textbox1. As you might have seen in the intellisense pop-up windows, there is a large number of properties that you can tweak and events that you can trigger. Notice the [.] notation for the TextElement in the code listing, FontFamily being the child of the parent TextElement. Listing 1 <TextBox HorizontalAlignment="Left" Margin="43,126,0,115" Name="TextBox1" Width="150" TextElement.FontFamily="Times Roman" ToolTip="Xaml TextBox" FontWeight="Bold" AutoWordSelection="True" Foreground="BlueViolet" Background="Aquamarine" TextDecorations="Underline" > </TextBox> When the program is executed you will see the following displayed. Summary The article describes the steps to create a WPF project. The Design <-->Declarative Code interactivity is also described. The placing of controls and adding event handling code to the code behind page is explained with an example. While testing the "AutoWordSelection" did not function as it should by its definition. You may look up this in the 'Help'.
Read more
  • 0
  • 0
  • 2117

article-image-users-profiles-and-connections-elgg
Packt
23 Oct 2009
8 min read
Save for later

Users, Profiles, and Connections in Elgg

Packt
23 Oct 2009
8 min read
Connecting to Friends and Users I hope you're convinced how important friends are to a social network. Initially, you'll have to manually invite your friends over to join. I say initially, because membership on a social network is viral. Once your friends are registered members of your network, they can also bring in their own friends. This means that soon your friends would have invited their own friends as well. Chances are that you might not know these friends of your friends. So, Elgg not only allows you to invite friends from outside, but also connect with users already on the network. Let's understand these situations in real-life terms. You invite your friends over to a party with you at your new Star Trek themed club. That's what you'll do with Elgg, initially. So your friends like the place and next time around they bring in more friends from work. These friends of friends from work talk about your place with their friends and so on, until you're hosting a bunch of people in the club that you haven't ever met in your life. You overhear some people discussing Geordi La Forge, your favorite character from the show. You invite them over for drinks. That's connecting with users already on the network. So let's head on over to Elgg and invite some friends! Inviting Friends to Join There are two ways of inviting users to join your network. Either send them an email with a link to join the website, or let Elgg handle sending them emails. If you send them emails, you can include a direct link to the registration page. This link is also on the front page of your network, which every visitor will see. It asks visitors to register an account if they like what's on the network. Let Elgg Handle Registration This is the most popular method of inviting users to join the network. It's accessible not only to you, but also to your friends once they've registered with the network. To allow Elgg to send emails on your behalf, you'll have to be logged into Elgg. Once you login, click on the Your Network button on the top navigation bar. This will take you to a page, which links to tools that'll help you connect with others. The last link in this bar (Invite a Friend) does exactly what it says. When you click on this link, it'll explain to you some benefits of inviting friends over. The page has three fields; Their name: Enter the name of the friend you're sending the invitation to. Their email address: Very important. This is the address to where the invitation is sent. An optional message: Elgg sends an email composed using a template. If you want to add a personal message to Elgg's email, you can do so here. In the email, which Elgg sends on behalf of the network's administrator, that means you, it displays the optional message (if you've sent one), along with a link to the registration page. The invitation is valid for seven days, after which the registration link in the email isn't valid. When your friends click on the registration form, it asks them to enter their: Name: This is your friend's real name. When he arrives here by clicking the link in the email, this field already has the same name as the one in the email. Of course, your friend can choose to change it if he pleases. Username: The name your friend wants to use to log in to the network. Elgg automatically suggests one based on your friend's real name. Password: The last two fields ask your friend to enter (and then re-enter to confirm) a password. This is used along with the username to authenticate him on the system. Once your friends enter all the details and click on join, Elgg creates an account for them, logs them in, and dispatches a message to them containing the log in details for reference. Build a Profile The first thing a new user has to do on the network is to create his profile. If you haven't yet built up a profile yourself, now is a good time. To recap, your profile is your digital self. By filling in a form, Elgg helps you define yourself in terms that'll help other members find and connect to you. This is again where socializing using Elgg outscores socializing in real life. You can find people with similar tastes, likes, and dislikes, as soon as you enter the network. So let's steam ahead and create a digital you. The Various Profile Options Once you are logged into your Elgg network, select the Your Profile option from the top navigation-bar. In the page that opens, click the first link, Edit this profile. This opens up a form, divided into five tabs—Basic details, Location, Contact, Employment, and Education. Each tab helps you fill in details regarding that particular area. You don't necessarily have to fill in each and every detail. And you definitely don't have to fill them all in one go. Each tab has a Save your profile button at the end. When you press this button, Elgg updates your profile instantaneously. You can fill in as much detail as you want, and keep coming back to edit your profile, and append new information. Let's look at the various tabs: Basic details: Although filling information in any tab is optional, I'd advise you to fill in all details in this tab. This will make it easy, for you to find others, and for others to find you. The tab basically asks you to introduce yourself, list your interests, your likes, your dislikes, your goals in life, and your main skills. Location: This tab requests information that'll help members reach you physically. Fill in your street address, town, state, postal code, and country. Contact: Do you want members to contact you outside your Elgg network? This tab requests both physical as well as electronic means which members can use to get in touch with you. Physical details include your work, home, and mobile telephone number. Electronic details include your email address, your personal, and official websites. Elgg can also list information to help users connect to you on instant messenger. It supports ICQ, MSN, AIM, Skype, and Jabber. Employment: List your occupation, the industry, and company you work in, your job title, and description. Elgg also lets you list your career goals and suggests you do so to "let colleagues and potential employers know what you'd like to get out of your career. Education: Here you can specify your level of education, and which high school, university or college you attended, and the degree you hold. As you can clearly see, Elgg's profiling options are very diverse and detailed. Rather than serve the sole purpose of describing you to the visitors, the profile also helps you find new friends as well, as we'll see later in this article. What is FOAF? While filling the profile, you must have noticed an Upload a FOAF file area down at the bottom of all tabs. FOAF or Friend of a Friend is a project (http://www.foaf-project.org/) to help create "machine-readable pages that describe people, the links between them, and the things they create, and do". The FOAF file includes lots of details about you, and if you have already created a FOAF profile, Elgg can use that to pick out information describing you from in there. You can modify the information once it's imported into Elgg, if you feel the need to do so. The FOAF-a-Matic tool (http://www.ldodds.com/foaf/foaf-a-matic.en.html) is a simple Web-based program you can use to create a FOAF profile. A Face for Your Profile Once you have created your digital self, why not give it a face as well. The default Elgg picture with a question mark doesn't look like you! To upload your picture, head over to Your Profile and select the Change site picture link. From this page, click Browse to find and select the picture on your computer. Put in an optional description, and then choose to make it your default icon. When you click the Upload new icon button, Elgg will upload the picture. Once the upload completes, Elgg will display the picture. Click the Save button to replace Elgg's default icon with this picture.   Elgg will automatically resize your picture to fit into its small area. You should use a close-up of yourself, otherwise the picture will lose clarity when resizing. If you don't like the picture when it appears on the website, or you want to replace it with a new one, simply tick the Delete check-box associated with the picture you don't like. When you click Save, Elgg will revert to the default question-mark guy.
Read more
  • 0
  • 0
  • 4695

article-image-using-data-pager-control-visual-studio-2008
Packt
23 Oct 2009
5 min read
Save for later

Using the Data Pager Control in Visual Studio 2008

Packt
23 Oct 2009
5 min read
A direct connection to SQL Server 2008 is not possible with this version of SQL Server and Visual Studio 2008. One way to get around this is to use an ODBC connection to the SQL Server and then using the ODBC connection to retrieve the data. Another way described is to use the OLEDB connectivity option shown in this article. Article Overview We first create an ASP.NET Web Application project. To the default.aspx page we add a ListView control. Then we configure the ListView Control by configuring its data source and its displayed features. At this point a DataPager can be included as part of the ListView, but adding a DataPager manually is also shown. Controlling the number of displayed items in a page can be carried out using page load event code or declaratively. Creating an ASP.NET Web Application From the File menu item create a new project that opens up the window shown in the next figure. Make sure you are creating a .NET Framework 3.5 ASP.NET Web application project (use drop-down at top right of this window). The default name of the application has been changed to DataPager as shown. Click on the OK button to create the project. The project is created with all the necessary files and the template for the Default.aspx page as shown. The Solution Explorer and the Class View of the project has all the information on this project. The Split tab at the bottom of the 'Default.aspx' shows both the Design page as well as the HTML code for the page. Adding a ListView Control and connecting to a Data Source Drag and drop a ListView Control from the Toolbox on to the design page between the <div/> tags as shown. The Code is automatically generated as shown in the next figure. The ListView instance has a Id property "ListView1". Now you can configure the ListView using the Smart Tasks handle - the small arrow head [>] attached to the list view at the top right. Click the Smart Task handle to open the list of tasks to be performed as shown. The only task you find here is the "Choosing the data source". Configuring the Data Source Now click on <New data source...>. This opens the Data Source Configuration Wizard. Click on Database icon which sets the stage for bringing data from SQL Server with an Id property "SQLDataSource1". This supports connecting to any ADO.NET datasource. Click on the OK button in the above window. This opens the window where you need to choose the "Connection String", a very important item for connecting to a source of data.     Click on the <New Connection...> button. This opens the Add Connection window with the default options displayed. Click on the Change... button since we are interested in connecting to SQL Server 2008. Click on the <other> drop-down menu item and choose the .NET Framework Data Provider for OLEDB as shown. Click on the OK button. This brings you back to the Add Connection window and you need to indicate the DataLinks. Click on the OLEDB Providers drop-down and choose Microsoft OLEDB Provider for SQL server as shown. Click on the Data Links... button. This brings up the Data Link Properties window as shown. Choose the Windows authentication. If you click on the drop-down handle for Selecting the databases on the server a list of databases will be displayed. Choose the pubsx database. Click on the OK on the Data Link properties page which will take you back to the Add Connection window updating all the information. You may test and verify the connection on this page as well. Click on the OK button on the Add Connection window. This will take you back to the Configure Data Source window seen earlier after updating the connection string as shown. Click on the Next button. The window that shows up is about saving the connection information to the web.config file. Make sure you read the notes on this window. Click on the Next button. In the window that gets displayed you can choose either a table from the database, or provide a SQL statement, or the name of a stored procedure. Here to keep it simple, the authors table is chosen from the drop-down list. You can make use of other buttons on this window to refine your select statement. Here just the table name is chosen. From the columns that are displayed a few columns are chosen. Click on the Next button. This displays the window where you can test your query. It comes up blank, but when you hit the button Test Query, the blank area gets populated by the result returned by the query as shown. Now click on the Finish button. This closes this window and the details of the just finished data source gets into the designer interface as shown.  
Read more
  • 0
  • 0
  • 2590

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-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-microsoft-sql-server-2008-installation-made-easy
Packt
23 Oct 2009
3 min read
Save for later

Microsoft SQL Server 2008 - Installation Made Easy

Packt
23 Oct 2009
3 min read
(For more resources on Microsoft, see here.) Initial State of Computer Assuming you are working with the Windows XP OS, it will be advisable to create a restore point to which you can fall back should you fail to install and something goes wrong. You can set up a fall back position by going to Start | All Programs | Accessories | System Tools | System Restore. This allows you to comeback where you were before starting the install. The other thing that you should lookup is the suite of Microsoft software you already have on your computer that may interfere with the product you are installing. This can be reviewed following Start | Control Panel | Add and Remove Programs. SQL 2008 server requires IE 6.0 or higher version. It may be helpful to install this before embarking on installing the SQL 2008 Server. For the purpose of this article IE 7.0 was installed. It has appeared in some forum topics that SQL 2008 can exist side-by-side with SQL 2005 server. However in the present case SQL 2005 was completely removed. Sometimes even this removal is not quite an easy process if something is broken in the original install and requires you to reinstall and then uninstall. In the case of SQL Server 2008, there was an earlier version, "Katmai", installed but never used due to its inability to connect to the SQL Server Management Studio (Well, unless you remove the SQL 2005 client you cannot install SQL 2008 Client), a fact which came to light much later. 'Katmai' components were completely removed which required reinstalling the 'Katmai' followed by its complete removal. When you download the SQL 2008 and run the executable, it creates the folder, servers, containing a number of subfolders and files (dynamic link library files etc) that are used during the installation. Help can be accessed from servershelp1033s10ch_setup, an HTML file which provides a wealth of information regarding all aspects of installation including migration from an earlier version. From servesdefault.htm you can begin the installation which provides the required support using Prepare | Install | Other information navigational aid. After removing all the suggested components during this installation, the remaining Microsoft SQL Server related components on the computer are as shown in the Add and Remove Programs window in the next figure. The very first screen you will see when you click on the serverssetup.exe file is the SQL Server 2008 Setup where you need to agree with the licensing terms before proceeding. When you click on the Next button which displays the Installation Pre-requisites screen, you will be shown the pending items needed before you install SQL 2008 server. Click on the Install button after highlighting the pending item regarding setup support files in the right screen. SQL Server Installation Center This will take you to the SQL Server Installation Center screen as shown. It has a number of useful hyperlinks that you can come back to by repeating the above steps. Click on New Installation link. This Starts Install SQL Server 2008 Wizard for System Configuration Check. After a while when the checking is completed the following screen will be displayed. This timeall items have the status marked 'Passed'. In a previous attempt when the 'Katmai' items were still uninstalled,the Previous CTP Install Check did not succeed and it was corrected only after completely removing those items. Clicking on Next button takes you to screen where you need to select the features that you want to have installed as shown. The display shows Features Selection window after all items have been checked.
Read more
  • 0
  • 0
  • 4074

article-image-aspnet-repeater-control
Packt
23 Oct 2009
6 min read
Save for later

The ASP.NET Repeater Control

Packt
23 Oct 2009
6 min read
The Repeater control in ASP.NET is a data-bound container control that can be used to automate the display of a collection of repeated list items. These items can be bound to either of the following data sources: Database Table XML File In a Repeater control, the data is rendered as DataItems that are defined using one or more templates. You can even use HTML tags such as <li>, <ul>, or <div> if required. Similar to the DataGrid, DataList, or GridView controls, the Repeater control has a DataSource property that is used to set the DataSource of this control to any ICollection, IEnumerable, or IListSource instance. Once this is set, the data from one of these types of data sources can be easily bound to the Repeater control using itsDataBind() method. However, the Repeater control by itself does not support paging or editing of data. The Repeater control is light weight and does not contain so many features as the DataGrid contains. However, it enables you to place HTML code in its templates. It is great in situations where you need to display the data quickly and format the data to be displayed easily. Using the Repeater Control The Repeater control is a data-bound control that uses templates to display data. It does not have any built-in support for paging, editing, or sorting of the data that is rendered through one or more of its templates. The Repeater control works by looping through the records in your data source and then repeating the rendering of one of its templates called the ItemTemplate, one that contains the records that the control needs to render. To use this control, drag and drop the control in the design view of the web form onto a web form from the toolbox. Refer to the following screenshot: You can also drag and drop the Repeater control from the toolbox onto the source view directly. This is shown in the following screenshot: For customizing the behavior of this control, you have to use the built-in templates that this control comes with. These templates are actually blocks of HTML code. The Repeater control contains the following five templates: HeaderTemplate ItemTemplate AlternatingItemTemplate SeparatorTemplate FooterTemplate The following screenshot shows how a Repeater control looks when populated with data. Note that the templates (Header, Item, Footer, Alternate and Separator) have all been used. The following code snippet is an example of the order in which the templates of the Repeater control are used. <asp:Repeater id="repEmployee" runat="server"><HeaderTemplate>...</HeaderTemplate><ItemTemplate></ItemTemplate><FooterTemplate>...</FooterTemplate></asp:Repeater> When the Repeater control is bound to a data source, the data from the data source is displayed using the ItemTemplate element and any other optional elements, if used. Note that the contents of the HeaderTemplate and the FooterTemplate are rendered once for each Repeater control. The contents of the ItemTemplate are rendered for each record in the control. You can also use the additional AlternatingItemTemplate element after the ItemTemplate element for specifying the appearance of each alternate record. You can also use the SeparatorTemplate element between each record for specifying the separators for the records. Displaying Data Using the Repeater Control This section discusses how we can display data using the Repeater control. As discussed earlier, the Repeater control uses templates for formatting the data that it displays. The following code snippet displays the code in an .aspx file that contains a Repeater control. Note that we would be making use of templates and that the data would be bound to the control from the code-behind file using the DataManager class. The Repeater control is populated with data in the Page_Load event by reusing the DataManager(). Note how the SeparatorTemplate and the AlternatingItemTemplate have been used in the previous code example. Further, the DataBinder.Eval() method has been used to display the values of the corresponding fields from the data container, (in our case, the DataSet instance) in the Repeater control. The FooterTemplate uses the Total Records variable and substitutes its value to display the total number of records displayed by the control. The following is the output on execution. The Header and the Footer templates of the Repeater control are still rendered even if the data source does not contain any data. If you want to suppress their display, you can use the Visible property of the Repeater control and use it to suppress the display of these templates with a simple logic. Here is how you specify the Visible property of this control in your .aspx file to achieve this_Visible="<%# Repeater1.Items.Count > 0 %>"When you specify the Visible property as shown here, the Repeater is made visible only if there are records in your data source.   Displaying Checkboxes in a Repeater Control Let us now understand how we can display checkboxes in a Repeater Control and retrieve the number of checked items. We will use a Button control and a Label control in our page. When you click on the Button control, the number of checked items in the Repeater Control will be displayed in the Label control. The output on execution is similar to what is shown in the following screenshot: Here is the code that we will use in the .aspx file to display checkboxes in a Repeater control. The data is bound to the Repeater control in the Page_Load event as follows: Note that we have used the Page.IsPostBack to check whether the page has posted back in the Page_Load method. If you don't bind data by checking whether the page has posted back, the Repeater control will be rebound to data once again after a postback and all the checkboxes in your web page will be reset to the unchecked state. The source code for the click event of the Button control that we have used is as follows: When you execute the application, the Repeater control is displayed with records from the employee table. Now you check one or more of the checkboxes and then click on the Button control just beneath the Repeater control as follows: Note that the number of checked records is displayed in the Label Control. Summary This article discussed the Repeater control and how we can use it in ourASP.NET applications. Though this control does not support all the functionalities of other data controls, like DataGrid and GridView, it is still a good choice if you want faster rendering of data as it is light weight, and is very flexible.
Read more
  • 0
  • 0
  • 5278
article-image-tapestry-5-advanced-components
Packt
23 Oct 2009
10 min read
Save for later

Tapestry 5 Advanced Components

Packt
23 Oct 2009
10 min read
Following are some of the components, we'll examine in Tapestry 5: The Grid component allows us to display different data in a fairly sophisticated table. We are going to use it to display our collection of celebrities. The BeanEditForm component greatly simplifies creating forms for accepting user input. We shall use it for adding a new celebrity to our collection. The DateField component provides an easy and attractive way to enter or edit the date. The FCKEditor component is a rich text editor, and it is as easy to incorporate into a Tapestry 5 web application, just as a basic TextField is. This is a third party component, and the main point here is to show that using a library of custom components in a Tapestry 5 application requires no extra effort. It is likely that a similar core component will appear in a future version of the framework. Grid Component It is possible to display our collection of celebrities with the help of the Loop component. It isn't difficult, and in many cases, that will be exactly the solution you need for the task at hand. But, as the number of displayed items grow (our collection grows) different problems may arise. We might not want to display the whole collection on one page, so we'll need some kind of pagination mechanism and some controls to enable navigation from page to page. Also, it would be convenient to be able to sort celebrities by first name, last name, occupation, and so on. All this can be achieved by adding more controls and more code to finally achieve the result that we want, but a table with pagination and sorted columns is a very common part of a user interface, and recreating it each time wouldn't be efficient. Thankfully, the Grid component brings with it plenty of ready to use functionality, and it is very easy to deal with. Open the ShowAll.tml template in an IDE of your choice and remove the Loop component and all its content, together with the surrounding table: <table width="100%"> <tr t_type="loop" t_source="allCelebrities" t:value="celebrity"> <td> <a href="#" t_type="PageLink" t_page="Details" t:context="celebrity.id"> ${celebrity.lastName} </a> </td> <td>${celebrity.firstName}</td> <td> <t:output t_format="dateFormat" t:value="celebrity.dateOfBirth"/> </td> <td>${celebrity.occupation}</td> </tr> </table> In place of this code, add the following line: <t:grid t_source="allCelebrities"/> Run the application, log in to be able to view the collection, and you should see the following result: Quite an impressive result for a single short line of code, isn't it? Not only are our celebrities now displayed in a neatly formatted table, but also, we can sort the collection by clicking on the columns' headers. Also note that occupation now has only the first character capitalized—much better than the fully capitalized version we had before. Here, we see the results of some clever guesses on Tapestry's side. The only required parameter of the Grid component is source, the same as the required parameter of the Loop component. Through this parameter, Grid receives a number of objects of the same class. It takes the first object of this collection and finds out its properties. It tries to create a column for each property, transforming the property's name for the column's header (for example, lastName property name gives Last Name column header) and makes some additional sensible adjustments like changing the case of the occupation property values in our example. All this is quite impressive, but the table, as it is displayed now, has a number of deficiencies: All celebrities are displayed on one page, while we wanted to see how pagination works. This is because the default number of records per page for  Grid component is 25—more than we have in our collection at the moment. The last name of the celebrities does not provide a link to the Details page anymore. It doesn't make sense to show the Id column. The order of the columns is wrong. It would be more sensible to have the Last Name in the first column, then First Name, and finally the Date of Birth. By default, to define the display of the order of columns in the table, Tapestry will use the order in which getter methods are defined in the displayed class. In the Celebrity class, the getFirstName method is the first of the getters and so the First Name column will go first, and so on. There are also some other issues we might want to take care of, but let's first deal with these four. Tweaking the Grid First of all let's change the number of records per page. Just add the following parameter to the component's declaration: <t:grid t_source="allCelebrities" rowsPerPage="5"/> Run the application, and here is what you should see: You can now easily page through the records using the attractive pager control that appeared at the bottom of the table. If you would rather have the pager at the top, add another parameter to the Grid declaration: <t:grid t_source="allCelebrities" rowsPerPage="5" pagerPosition="top"/> You can even have two pagers, at the top and at the bottom, by specifying pagerPosition="both", or no pagers at all (pagerPosition="none"). In the latter case however, you will have to provide some custom way of paging through records. The next enhancement will be a link surrounding the celebrity's last name and linking to the Details page. We'll be adding an ActionLink and will need to know which Celebrity to link to, so we have the Grid store using the row parameter. This is how the Grid declaration will look: <t:grid t_source="allCelebrities" rowsPerPage="5" row="celebrity"/> As for the page class, we already have the celebrity property in it. It should have been left from our experiments with the Loop component. It will also be used in exactly the same way as with Loop, while iterating through the objects provided by its source parameter, Grid will assign the object that is used to display the current row to the celebrity property. The next thing to do is to tell Tapestry that when it comes to the contents of the Last Name column, we do not want Grid to display it in a default way. Instead, we shall provide our own way of displaying the cells of the table that contain the last name. Here is how we do this: <t:grid t_source="allCelebrities" rowsPerPage="5" row="celebrity"> <t:parameter name="lastNameCell"> <t:pagelink t_page="details" t_context="celebrity.id"> ${celebrity.lastName} </t:pagelink> </t:parameter> </t:grid> Here, the Grid component contains a special Tapestry element , similar to the one that we used in the previous chapter, inside the If component. As before, it serves to provide an alternative content to display, in this case, the content which will fill in the cells of the Last Name column. How does Tapestry know this? By the name of the element, lastNameCell. The first part of this name, lastName, is the name of one of the properties of the displayed objects. The last part, Cell, tells Tapestry that it is about the content of the table cells displaying the specified property. Finally, inside , you can see an expansion displaying the name of the current celebrity and surrounding it with the PageLink component that has for its context the ID of the current celebrity. Run the application, and you should see that we have achieved what we wanted: Click on the last name of a celebrity, and you should see the Details page with the appropriate details on it. All that is left now is to remove the unwanted Id column and to change the order of the remaining columns. For this, we'll use two properties of the Grid—remove and reorder. Modify the component's definition in the page template to look like this: <t:grid t_source="celebritySource" rowsPerPage="5" row="celebrity" remove="id" reorder="lastName,firstName,occupation,dateOfBirth"> <t:parameter name="lastNameCell"> <t:pagelink t_page="details" t_context="celebrity.id"> ${celebrity.lastName} </t:pagelink> </t:parameter> </t:grid> Please note that re-ordering doesn't delete columns. If you omit some columns while specifying their order, they will simply end up last in the table. Now, if you run the application, you should see that the table with a collection of celebrities is displayed exactly as we wanted: Changing the Column Titles Column titles are currently generated by Tapestry automatically. What if we want to have different titles? Say we want to have the title, Birth Date, instead of Date Of Birth. The easiest and the most efficient way to do this is to use the message catalog, the same one that we used while working with the Select component in the previous chapter. Add the following line to the app.properties file: dateOfBirth-label=Birth Date Run the application, and you will see that the column title has changed appropriately. This way, appending -label to the name of the property displayed by the column, you can create the key for a message catalog entry, and thus change the title of any column. Now you should be able to adjust the Grid component to most of the possible requirements and to display with its help many different kinds of objects. However, one scenario can still raise a problem. Add an output statement to the getAllCelebrities method in the ShowAll page class, like this: public List<Celebrity> getAllCelebrities() { System.out.println("Getting all celebrities..."); return dataSource.getAllCelebrities(); } The purpose of this is simply to be aware when the method is called. Run the application, log in, and as soon as the table with celebrities is shown, you will see the output, as follows: Getting all celebrities... The Grid component has the allCelebrities property defined as its source, so it invokes the getAllCelebrities method to obtain the content to display. Note however that Grid, after invoking this method, receives a list containing all 15 celebrities in collection, but displays only the first five. Click on the pager to view the second page—the same output will appear again. Grid requested for the whole collection again, and this time displayed only the second portion of five celebrities from it. Whenever we view another page, the whole collection is requested from the data source, but only one page of data is displayed. This is not too efficient but works for our purpose. Imagine, however, that our collection contains as many as 10,000 celebrities, and it's stored in a remote database. Requesting for the whole collection would put a lot of strain on our resources, especially if we are going to have 2,000 pages. We need to have the ability to request the celebrities, page-by-page—only the first five for the first page, only the second five for the second page and so on. This ability is supported by Tapestry. All we need to do is to provide an implementation of the GridDataSource interface. Here is a somewhat simplified example of such an implementation.
Read more
  • 0
  • 0
  • 3096

article-image-designing-and-creating-database-tables-ruby-rails
Packt
23 Oct 2009
9 min read
Save for later

Designing and Creating Database Tables in Ruby on Rails

Packt
23 Oct 2009
9 min read
Background Information The User Management Module is created for a website called 'TaleWiki'. TaleWiki is a website about user submitted tales and stories, which can be added, modified, deleted, and published by the user, depending on the Role or Privileges the user has. Taking into consideration this small piece of information, we will design and create tables that will become the back-end for the User Management functionality. Designing the Tables To Design and to create tables, we need to understand the entities and their relationship, the schema corresponding to the entities, and then the table creation queries. If we go step-by-step, we can say that following are the steps in designing the tables for the User Management module: Designing the E-R model Deriving the Schema from the E-R model Creating the Tables from the Schema So, let us follow the steps. Designing the E-R Model To design the E-R model, let us first look at what we have understood about the data required by the functionalities, which we just discussed. It tells us that 'only the Users with a particular Role can access TaleWiki'. Now we can consider this as our 'problem statement' for our E-R model design. If you observe closely, the statement is vague. It doesn't tell about the particular Roles. However, for the E-R design, this will suffice as it clearly mentions the two main entities, if we use the E-R terminology. They are: User Role Let us look at the User entity. Now this entity represents a real-world user. It is not difficult to describe its attributes. Keeping a real-world user in mind and the functionalities discussed for managing a user, we can say that the User entity should have the following attributes: Id: It will identify the different users, and it will be unique. User name: The name which will be displayed with the submitted story. Password: The pass key with which the user will be authenticated. First name: The first name of the user. Last name: The last name of the user. The combination of the first and last name will be the real name of the user. Age: The age of the user. This will help in deciding whether or not the user is of required age which is 15. E-mail id: The email id of the user in which he/she would like to get emails from the administrator regarding the submissions. Country: To keep track of the 'geographic distribution' of users. Role: To know what privileges are granted for the user. The Role is required because the problem statement mentions "User with a particular Role". The entity diagram will be as follows: Next, let us look at the Role entity. Role, as already discussed, will represent the privileges a user can have. And as these privileges are static, the Role entity won't need to have the attribute to store the privileges. The important point about the static privileges that you have to keep in mind is that they will have to be programmatically checked against a user. In other words, the privileges are not present in the database and there can only be a small number of Roles with predefined privileges. Keeping this in mind, we can say that the Role entity will have the following attributes: Id: The unique identification number for the Role. Name: The name with which the id will be known and that will be displayed along with the user name. The entity diagram for Role entity will be as follows: We have completed two out of three steps in designing the E-R model. Next, we have to define how the User entity is related with the Role entity. From the problem statement we can say that a user will definitely have a Role. And the functionality for assigning the Role tells us that a user can have only one Role. So if we combine these two, we can say that 'A user will have only one Role but different users can have the same Role'. In simple terms, a Role—let us say normal user—can be applied to different users such as John, or Jane. However, the users John or Jane cannot be both normal user as well as administrator. In technical terms, we can say that a Role has a one-to-many relationship with the User entity and a User has a many-to-one relationship with a Role. Diagrammatically, it will be as follows: One piece of the puzzle is still left. If you remember there is one more entity called Story. We had found that each story had a submitter. The submitter is a user. So that means there is a relationship between the User and the Story entity. Now, a user, let us say, John or Jane, can submit many stories. However, the same story cannot be submitted by more than one user. On the basis of this we can say that a User has a many-to-one relationship with a Story and a Story has a many-to-one relationship with a User. According to the E-R diagram it will be as follows: The final E-R design including all the entities and the attributes will be as follows: That completes our E-R design step. Next, we will derive the schema from theE-R model. Deriving the Schema We have all we need to derive the schema for our purpose. While deriving a schema from an E-R model, it is always a good choice to start with the entities at the 'one' end of a 'one-to-many' relationship. In our case, it is the Role entity. As we did in the previous chapter, let us start by providing the details for each attribute of the Role entity. The following is the schema for the Role entity: Attribute Data type of the attribute Length of the acceptable value Id Integer 10 Name Varchar 25 >Next, let us look at the schema of the User entity. As it is at the 'many' end of the 'one-to-many' relationship, the Role attribute will be replaced by the Id of Role. The schema will be as follows: Attribute Data type of the attribute Length of the acceptable value Id Integer 10 User name Varchar 50 First name Varchar 50 Last name Varchar 50 Password Varchar 15 Age Integer 3 e-mail id Varchar 25 Country Varchar 20 Id of the Role Integer 10 Now, let us visit the Story entity. The attributes of the entity were: Id: This is the Primary key attribute as it can uniquely identify a story. Heading: The title of the story. Body text: The body of the story. Date of Submission: The day the user submitted the story. Source: The source from where the story was found. If it is written by the user himself/herself, the source will be the user's id. Genre: The category of the story. User: The user who submitted the story. Name of the attribute Data type of the attribute Length of the acceptable value Id Integer 10 Title Varchar 100 Body Text Varchar 1000 Date of Submission Date   Source Varchar 50 Status Varchar 15 Id of Genre Integer 10 Id of the User Integer 10 The schema has been derived and now we can move to the last part of the database design—creation of the tables. Creating the Tables Looking at the schema  required for tables in Ruby on Rails, here is the table creation statement for the Role schema: CREATE TABLE `roles` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,`name` VARCHAR( 25 ) NOT NULL ,`description` VARCHAR( 100 ) NOT NULL) ENGINE = innodb; Next comes the table creation statement for the User schema. Note that here also we are following the one-to-many path, that is, the table at the 'one' end is created first. Whenever there is a one-to-many relationship between entities, you will have to create the table for the entity at the 'one' end. Otherwise you will not be able to create a foreign key reference in the table for the entity at the 'many' end, and if you try to create one, you will get an error (obviously). So here is the create table statement for the User schema: CREATE TABLE `users` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,`user_name` VARCHAR( 50 ) NOT NULL ,`password` VARCHAR( 15 ) NOT NULL ,`first_name` VARCHAR( 50 ) NOT NULL ,`last_name` VARCHAR( 50 ) NOT NULL ,`age` INT( 3 ) NOT NULL ,`email` VARCHAR( 25 ) NOT NULL ,`country` VARCHAR( 20 ) NOT NULL ,`role_id` INT NOT NULL,CONSTRAINT `fk_users_roles` FOREIGN KEY (`role_id`) REFERENCES `role`( `id`) ON DELETE CASCADE) ENGINE = innodb; Next, let us create the table for Story, we will call it the 'tales' table, we will also add a foreign key reference to the users table in it. Here is the query for creating the table CREATE TABLE `tales` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,`title` VARCHAR( 100 ) NOT NULL,`body_text` TEXT NOT NULL,`submission_date` DATE NOT NULL,`source` VARCHAR( 50 ) NOT NULL,`status` VARCHAR( 15 ) NOT NULL,`genre_id` INT NOT NULL,`user_id` INT NOT NULL,CONSTRAINT `fk_tales_genres` FOREIGN KEY (`genre_id`) REFERENCES genres( `id`)) ENGINE = innodb; Next, we will make a reference to the users table after executing the above query, with the following query: ALTER TABLE `tales` ADD FOREIGN KEY ( `user_id` ) REFERENCES `users` (`id`) ON DELETE CASCADE ; That completes our task of creating the required tables and making necessary changes to the tales table. The effect of this change will be visible to you when we implement session management in the next chapter. And incidentally, it completes the 'designing the tables' section. Let us move onto the development of the user management functionality. Summary In this article, we learned how to design and create tables for a User Management Module in Ruby on Rails. We looked at designing the E-R model, deriving the schema from the E-R model and creating the tables from the schema.
Read more
  • 0
  • 0
  • 5065
Modal Close icon
Modal Close icon