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

How-To Tutorials

7019 Articles
article-image-web-services-soa-and-ws-bpel-technologies
Packt
22 Oct 2009
15 min read
Save for later

Web Services, SOA, and WS-BPEL Technologies

Packt
22 Oct 2009
15 min read
Nowadays, the most common way to build composite applications based on service-oriented principles is to use the Service-Oriented Architecture, Webservices, and WS-BPEL (Web Services Business Process Execution Language) technologies together. While Web Services is a technology that defines a standard mechanism for exposure and consumption of data and application logic over Internet protocols such as HTTP, WS-BPEL is an orchestration language that is used to define business processes describing Web services' interactions, thus providing a foundation for building SOA solutions based on Web services. So, to build an SOA solution utilizing Web services with WS-BPEL, you have to perform the following steps: Build and then publish Web services to be utilized within an SOA solution Compose the Web services into business flows with WS-BPEL This article gives an overview of the Web services, SOA, and WS-BPEL technologies and how these technologies are interrelated. It also contains references to related documentation and other chapters of the book SOA and WS-BPEL, which discuss the topics touched upon in this introductory article in greater detail. Web Services The Web Services technology provides an efficient way to share application logic across multiple machines running various operating systems and using different development environments. To achieve this, Web Services utilizes the SOAP, WSDL, XML Schema, and some other XML-based technologies, providing a standards-based approach to overcoming the platform and language differences. The following sections give you an overview of these technologies, explaining how they fit into the big picture. Communicating via SOAP In a nutshell, SOAP is a messaging protocol used to transfer application data in XML format over a transport protocol, such as HTTP. Nowadays, Web service applications employ SOAP as a standard protocol for exchanging information in a decentralized, distributed manner. For detailed information about SOAP, you can refer the W3C SOAP Recommendation documents. Links to these documents can be found at http://www.w3.org/TR/soap/. SOAP-based interfaces interact with each other by means of SOAP messages that are specially formatted XML documents used to carry data and metadata. The general structure of a SOAP message is shown below: <SOAP-ENV:Envelope ...> <SOAP_ENV:Header> ... ... </SOAP_ENV:Header> <SOAP_ENV:Body> ... ... </SOAP_ENV:Body> </SOAP-ENV:Envelope ...> As you can see in the previous code snippet, an XML document representing a SOAP message consists of the following elements: An Envelope element wrapping the entire message. A Header element, which is actually optional and may contain subelements carrying metadata associated with the message. A Body element, which contains the payload of the message. This element may contain an optional fault element, which describes an error if it occurs. While SOAP messages may be used in various message exchange scenarios, the most popular one is the request/response pattern, which is normally used when calling a remote function exposed by a Web service. Diagrammatically, the request/response scenario might look like the following figure: As you can see in the above figure, both the service requestor and service provider include the message processing logic required to send/receive and process SOAP messages involved in the request/response scenario used here. If the service requestor is calling a remote function exposed by the service provider, the request message is supposed to carry the values of the parameters passed to the exposed function. After the request message is received, the service provider processes it, extracting the payload (in this case, the parameters passed to the function) from theenvelope. Then, the requested function is invoked, utilizing the parameters specified. Once the function result is ready, the service provider wraps this result in a SOAP envelope and sends it back to the service requestor in the response message. The service requestor in turn extracts the function result from the response message and sends it to the calling code. In Chapter 2 of the book SOA and WS-BPEL, you will learn how to implement service providers andservice requestors with PHP using the PHP SOAP extension. Now that you have a rough idea of how the remote procedure call (RPC) scenario works with SOAP, let's look at an example. Suppose you have a Web service that exposes the getOrderStatus function, taking the number of a purchase order as the parameter and returning the status of that order as the result. It is important to understand that the getOrderStatus function discussed in this example may be implemented in any programming language and run on any platform, provided they allow you to expose this function through SOAP. The fact is that Web services hide the details of underlying logic from their consumers, publicly exposing only their interfaces. In the book SOA and WS-BPEL, you will see a few examples of implementing service underlying logic with PHP. The following figure depicts a scenario where a service requestor invokes the getOrderStatus function exposed as a Web service: The general steps performed at run time are the following: The service requestor sends a SOAP request message containing the number of a purchase order to the service provider. The service provider processes the request message, extracting the PO number from the SOAP envelope. The service provider invokes the getOrderStatus underlying function, passing the extracted PO number as the parameter. The service provider encapsulates the result produced by the getOrderStatus function into a SOAP response message. The service provider sends the SOAP response message back to the requestor. In this example, the SOAP request message sent to the Web service provider might look like the following: <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope > <SOAP-ENV:Body> <SOAP-ENV:getOrderStatus> <body>US-247860</body> </SOAP-ENV:getOrderStatus> </SOAP-ENV:Body> </SOAP-ENV:Envelope> As you can see, the body of the above SOAP message contains the purchase order number passed as the parameter to the getOrderStatus function. The response to this message might look like the following: <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope > <SOAP-ENV:Body> <SOAP-ENV:getOrderStatusResponse> <body>Shipped</body> </SOAP-ENV:getOrderStatusResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> The getOrderStatus function may be designed so that it throws a SOAP exception when something goes wrong. For example, an exception may be thrown upon a failure to connect to the database that contains information about the purchase orders placed. A fault message generated by the Web service exposing the getOrderStatus function might look like the following: <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope > <SOAP-ENV:Body> <SOAP-ENV:Fault> <faultcode>SOAP-ENV:Server</faultcode> <faultstring>Failed to determine the order status</faultstring> </SOAP-ENV:Fault> </SOAP-ENV:Body> </SOAP-ENV:Envelope> As you can see, the fault section resides within the body section of the message, and includes two subelements detailing the fault that occurred, namely: faultcode and faultstring. Binding with WSDL Looking through the SOAP request message discussed in the preceding section, you may notice that it carries only the parameter for the getOrderStatus function exposed by the service. The message doesn't actually contain any information about how to get to the service, what remote function is to be invoked, and what that function is to return. Obviously, there must be another document that describes the Web service, providing all this information to consumers of the service. Web Services Description Language (WSDL) provides a mechanism to describe Web services, making them available for external consumption. A WSDL service description is an XML document that defines how to communicate with the Web service, describing the way in which that Web service has to be consumed. For detailed information about WSDL, you can refer to the WebServices Description Language (WSDL) W3C Note available athttp://www.w3.org/TR/wsdl. Actually, a WSDL service description document consists of two parts: logical and physical. The logical part of a WSDL describes the abstract characteristics of a Web service and includes the following sections: types is an optional section in which you can define types for the data being carried, normally using the XSD type system. message contains one or more logical parts representing input and output parameters being used with an operation. operation describes an action performed by the service, specifying input and output messages being used as parameters of the operation. portType establishes an abstract set of operations supported by the service. The physical part of a WSDL describes the concrete characteristics of a Web service and includes the following sections: binding associates a concrete protocol and message format specifications to operations and messages defined within a particular port type established in the logical part of the document. port establishes an endpoint by associating a binding with a concrete network address. service contains one or more port elements representing related endpoints. Turning back to the example discussed in the preceding section, the WSDL description document that describes the Web service exposing the getOrderStatus function might look like the following: <?xml version="1.0" encoding="utf-8"?><definitions name ="poService" targetNamespace="http://localhost/WebServices/ch1/poService"> <message name="getOrderStatusInput"> <part name="body" element="xsd:string"/> </message> <message name="getOrderStatusOutput"> <part name="body" element="xsd:string"/> </message> <portType name="poServicePortType"> <operation name="getOrderStatus"> <input message="tns:getOrderStatusInput"/> <output message="tns:getOrderStatusOutput"/> </operation> </portType> <binding name="poServiceBinding" type="tns:poServicePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getOrderStatus"> <soap:operation soapAction= "http://localhost/WebServices/ch1/getOrderStatus"/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="poService"> <port name="poServicePort" binding="tns:poServiceBinding"> <soap:address location= "http://localhost/WebServices/ch1/SOAPserver.php"/> </port> </service></definitions> Let's go through this document in detail to understand the format of a WSDL description document. The definitions element is the root in every WSDL document, wrapping all the WSDL definitions used in the document. Also, it houses the namespaces used within the document: <definitions name ="poService" targetNamespace= "http://localhost/WebServices/ch1/poService"> Next, you define the abstract definitions for the messages to be used for exchanging data. Here is the abstract definition for the message that will be used for carrying the input parameter for the getOrderStatus function: <message name="getOrderStatusInput"> <part name="body" element="xsd:string"/> </message> Here is the abstract definition for the message to be used for sending back the result of the getOrderStatus function: <message name="getOrderStatusOutput"> <part name="body" element="xsd:string"/> </message> Once you have messages defined, you can group them into operations, which in turn are grouped into a service interface. Here is the portType section representing an abstract view of the service interface, which, in this example, supports onlyone operation: <portType name="poServicePortType"> <operation name="getOrderStatus"> <input message="tns:getOrderStatusInput"/> <output message="tns:getOrderStatusOutput"/> </operation> </portType> Now that you have an abstract service interface defined, you can go ahead and specify physical details of the data exchange. In a binding section, you map the abstract service interface defined within a portType section earlier into a concrete format, specifying the concrete protocol for data transmission and message format specifications. In this example, the binding section is used to deploy thegetOrderStatus operation—the only operation supported by the service: <binding name="poServiceBinding" type="tns:poServicePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getOrderStatus"> <soap:operation soapAction= "http://localhost/WebServices/ch1/getOrderStatus"/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> In the above snippet, you define a SOAP binding of the request-response RPC operation over HTTP and specify the concrete URI indicating the purpose of the SOAP HTTP request. Finally, you use the service element hosting the port element to specify the physical address of the service. <service name="poService"> <port name="poServicePort" binding="tns:poServiceBinding"> <soap:address location= "http://localhost/WebServices/ch1/SOAPServer.php"/> </port> </service> In the above example, the getOrderStatus function exposed as a Web service takes only one input parameter. But what if you need to pass more than one parameter to a Web service? Suppose you modify the getOrderStatus function so that it takes one more parameter, say, poDate specifying the date an order was placed. If so, you have to include a new part element to the message construct describing the logical abstract content of an input message in the WSDL document: <definitions name ="poService" targetNamespace= "http://localhost/WebServices/ch1/poService"> <message name="getOrderStatusInput"> <part name="poNumber" element="xsd:string"/> <part name="poDate" element="xsd:string"/> </message> <message name="getOrderStatusOutput"> <part name="body" element="xsd:string"/> </message> ... </definitions> Now, a SOAP message issued by a service requestor when calling the getOrderStatus remote function would look as follows: <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope > <SOAP-ENV:Body> <SOAP-ENV:getOrderStatus> <poNumber>US-247860</poNumber> <poDate>21-jan-07</poDate> </SOAP-ENV:getOrderStatus> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Using XML Schema Types within WSDL Definitions As you might notice, the WSDL document discussed in the preceding section doesn't contain the types construct. It is OK in this particular example because you don't actually need any custom XML Schema Definition (XSD) types when defining message parts in the WSDL document. Instead, you use the native XSD schema type string. However, in some situations you may find it useful to utilize custom XML Schema types within a WSDL document. You can define custom XSD types within the types construct of a WSDL document and then reference them within message elements. For example, you might define a complex XSD type in the types section of the WSDL document discussed in the previous section and then reference this XSD type when creating the abstract definition of the output message: <?xml version="1.0" encoding="utf-8"?> <definitions name ="poService" targetNamespace= "http://localhost/WebServices/ch1/po.wsdl"> <types> <xsd:schema targetNamespace="http://localhost/WebServices/schema/"> <xsd:element name="poInfo"> <xsd:complexType> <xsd:sequence> <xsd:element name="pono" type="xsd:string" /> <xsd:element name="shippingDate" type="xsd:string" /> <xsd:element name="status" type="xsd:string" /> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </types> <message name="getOrderStatusInput"> <part name="poNumber" element="xsd:string"/> <part name="poDate" element="xsd:string"/> </message> <message name="getOrderStatusOutput"> <part name="poStatus" element="xsd1:poInfo"/> </message> ... </definitions> In this example, a response message sent by the service to a service request or mightlook as follows: <SOAP-ENV:Envelope > <SOAP-ENV:Body> <SOAP-ENV:getOrderStatusResponse> <poStatus> <pono>US-247860</pono> <shippingDate>21-jan-07</shippingDate> <status>Shipped</status> </poStatus> </SOAP-ENV:getOrderStatusResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> While this example shows how to define custom XML Schema types within the types construct of a WSDL document, you can achieve better reusability by putting XSD type definitions in a single XSD document. Continuing with this example, you might remove the contents of the types construct into a separate file so that it's available, say, at http://localhost/WebServices/schema/po.xsd. The contents of this file should look as follows: <?xml version="1.0"?> <schema targetNamespace="http://localhost/WebServices/schema/" > <element name="poInfo"> <complexType> <sequence> <element name="pono" type="string" /> <element name="shippingDate" type="string" /> <element name="status" type="string" /> </sequence> </complexType> </element> </schema> </schema> With that done, you can make use of the import statement in the WSDL documentin order to associate the namespace representing the custom XSD schema with the location of the above document, thus making the contents of the schema available within the WSDL document: <?xml version="1.0" encoding="utf-8"?> <definitions name ="poService" targetNamespace= "http://localhost/WebServices/ch1/po.wsdl"> <import namespace="http://localhost/WebServices/schema/" location="http://localhost/WebServices/schema/po.xsd"/> <message name="getOrderStatusInput"> <part name="poNumber" element="xsd:string"/> <part name="poDate" element="xsd:string"/> </message> <message name="getOrderStatusOutput"> <part name="poStatus" element="xsd1:poInfo"/> </message> ... </definitions> As you no doubt have realized, having XSD type definitions in separate files allows you to build more flexible, reusable, and modular solutions. In Chapter 3 of the book SOA and WS-BPEL, you will see how the XSD documents referenced in WSDL can be then reused by an Oracle database holding and processing SOAPmessages data.
Read more
  • 0
  • 0
  • 4113

article-image-aspnet-social-networks-making-friends-part-2
Packt
22 Oct 2009
18 min read
Save for later

ASP.NET Social Networks—Making Friends (Part 2)

Packt
22 Oct 2009
18 min read
Implementing the presentation layer Now that we have the base framework in place, we can start to discuss what it will take to put it all together. Searching for friends Let's see what it takes to implement a search for friends. SiteMaster Let's begin with searching for friends. We haven't covered too much regarding the actual UI and nothing regarding the master page of this site. Putting in simple words, we have added a text box and a button to the master page to take in a search phrase. When the button is clicked, this method in the MasterPage code behind is fired. protected void ibSearch_Click(object sender, EventArgs e){ _redirector.GoToSearch(txtSearch.Text);} As you can see it simply calls the Redirector class and routes the user to the Search.aspx page passing in the value of txtSearch (as a query string parameter in this case). public void GoToSearch(string SearchText){ Redirect("~/Search.aspx?s=" + SearchText); } Search The Search.aspx page has no interface. It expects a value to be passed in from the previously discussed text box in the master page. With this text phrase we hit our AccountRepository and perform a search using the Contains() operator. The returned list of Accounts is then displayed on the page. For the most part, this page is all about MVP (Model View Presenter) plumbing. Here is the repeater that displays all our data. <%@ Register Src="~/UserControls/ProfileDisplay.ascx" TagPrefix="Fisharoo" TagName="ProfileDisplay" %>...<asp:Repeater ID="repAccounts" runat="server" OnItemDataBound="repAccounts_ItemDataBound"> <ItemTemplate> <Fisharoo:ProfileDisplay ShowDeleteButton="false" ID="pdProfileDisplay" runat="server"> </Fisharoo:ProfileDisplay> </ItemTemplate></asp:Repeater> The fun stuff in this case comes in the form of the ProfileDisplay user control that was created so that we have an easy way to display profile data in various places with one chunk of reusable code that will allow us to make global changes. A user control is like a small self-contained page that you can then insert into your page (or master page). It has its own UI and it has its own code behind (so make sure it also gets its own MVP plumbing!). Also, like a page, it is at the end of the day a simple object, which means that it can have properties, methods, and everything else that you might think to use. Once you have defined a user control you can use it in a few ways. You can programmatically load it using the LoadControl() method and then use it like you would use any other object in a page environment. Or like we did here, you can add a page declaration that registers the control for use in that page. You will notice that we specified where the source for this control lives. Then we gave it a tag prefix and a tag name (similar to using asp:Control). From that point onwards we can refer to our control in the same way that we can declare a TextBox! You should see that we have <Fisharoo:ProfileDisplay ... />. You will also notice that our tag has custom properties that are set in the tag definition. In this case you see ShowDeleteButton="false". Here is the user control code in order of display, code behind, and the presenter: //UserControls/ProfileDisplay.ascx<%@ Import namespace="Fisharoo.FisharooCore.Core.Domain"%><%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ProfileDisplay.ascx.cs" Inherits="Fisharoo.FisharooWeb.UserControls.ProfileDisplay" %><div style="float:left;"> <div style="height:130px;float:left;"> <a href="/Profiles/Profile.aspx?AccountID=<asp:Literal id='litAccountID' runat='server'></asp:Literal>"> <asp:Image style="padding:5px;width:100px;height:100px;" ImageAlign="Left" Width="100" Height="100" ID="imgAvatar" ImageUrl="~/images/ProfileAvatar/ProfileImage.aspx" runat="server" /></a> <asp:ImageButton ImageAlign="AbsMiddle" ID="ibInviteFriend" runat="server" Text="Become Friends" OnClick="lbInviteFriend_Click" ImageUrl="~/images/icon_friends.gif"></asp:ImageButton> <asp:ImageButton ImageAlign="AbsMiddle" ID="ibDelete" runat="server" OnClick="ibDelete_Click" ImageUrl="~/images/icon_close.gif" /><br /> <asp:Label ID="lblUsername" runat="server"></asp:Label><br /> <asp:Label ID="lblFirstName" runat="server"></asp:Label> <asp:Label ID="lblLastName" runat="server"></asp:Label><br /> Since: <asp:Label ID="lblCreateDate" runat="server"></asp:Label><br /> <asp:Label ID="lblFriendID" runat="server" Visible="false"></asp:Label> </div> </div>//UserControls/ProfileDisplay.ascx.csusing System;using System.Collections;using System.Configuration;using System.Data;using System.Linq;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.HtmlControls;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Xml.Linq;using Fisharoo.FisharooCore.Core.Domain;using Fisharoo.FisharooWeb.UserControls.Interfaces;using Fisharoo.FisharooWeb.UserControls.Presenters;namespace Fisharoo.FisharooWeb.UserControls{ public partial class ProfileDisplay : System.Web.UI.UserControl, IProfileDisplay { private ProfileDisplayPresenter _presenter; protected Account _account; protected void Page_Load(object sender, EventArgs e) { _presenter = new ProfileDisplayPresenter(); _presenter.Init(this); ibDelete.Attributes.Add("onclick","javascript:return confirm('Are you sure you want to delete this friend?')"); } public bool ShowDeleteButton { set { ibDelete.Visible = value; } } public bool ShowFriendRequestButton { set { ibInviteFriend.Visible = value; } } public void LoadDisplay(Account account) { _account = account; ibInviteFriend.Attributes.Add("FriendsID",_account.AccountID.ToString()); ibDelete.Attributes.Add("FriendsID", _account.AccountID.ToString()); litAccountID.Text = account.AccountID.ToString(); lblLastName.Text = account.LastName; lblFirstName.Text = account.FirstName; lblCreateDate.Text = account.CreateDate.ToString(); imgAvatar.ImageUrl += "?AccountID=" + account.AccountID.ToString(); lblUsername.Text = account.Username; lblFriendID.Text = account.AccountID.ToString(); } protected void lbInviteFriend_Click(object sender, EventArgs e) { _presenter = new ProfileDisplayPresenter(); _presenter.Init(this); _presenter.SendFriendRequest(Convert.ToInt32(lblFriendID.Text)); } protected void ibDelete_Click(object sender, EventArgs e) { _presenter = new ProfileDisplayPresenter(); _presenter.Init(this); _presenter.DeleteFriend(Convert.ToInt32(lblFriendID.Text)); } }}//UserControls/Presenter/ProfileDisplayPresenter.csusing System;using System.Data;using System.Configuration;using System.Linq;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.HtmlControls;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Xml.Linq;using Fisharoo.FisharooCore.Core;using Fisharoo.FisharooCore.Core.DataAccess;using Fisharoo.FisharooWeb.UserControls.Interfaces;using StructureMap;namespace Fisharoo.FisharooWeb.UserControls.Presenters{ public class ProfileDisplayPresenter { private IProfileDisplay _view; private IRedirector _redirector; private IFriendRepository _friendRepository; private IUserSession _userSession; public ProfileDisplayPresenter() { _redirector = ObjectFactory.GetInstance<IRedirector>(); _friendRepository = ObjectFactory.GetInstance<IFriendRepository>(); _userSession = ObjectFactory.GetInstance<IUserSession>(); } public void Init(IProfileDisplay view) { _view = view; } public void SendFriendRequest(Int32 AccountIdToInvite) { _redirector.GoToFriendsInviteFriends(AccountIdToInvite); } public void DeleteFriend(Int32 FriendID) { if (_userSession.CurrentUser != null) { _friendRepository.DeleteFriendByID(_userSession.CurrentUser.AccountID , FriendID); HttpContext.Current.Response.Redirect(HttpContext.Current.Request.Raw Url); } } }} All this logic and display is very standard. You have the MVP plumbing, which makes up most of it. Outside of that you will notice that the ProfileDisplay control has a LoadDisplay() method responsible for loading the UI for that control. In the Search page this is done in the repAccounts_ItemDataBound() method. protected void repAccounts_ItemDataBound(object sender, RepeaterItemEventArgs e){ if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) { ProfileDisplay pd = e.Item.FindControl("pdProfileDisplay") as ProfileDisplay; pd.LoadDisplay((Account)e.Item.DataItem); if(_webContext.CurrentUser == null) pd.ShowFriendRequestButton = false; }} The ProfileDisplay control also has a couple of properties one to show/hide the delete friend button and the other to show/hide the invite friend button. These buttons are not appropriate for every page that the control is used in. In the search results page we want to hide the Delete button as the results are not necessarily friends. We would want to be able to invite them in that view. However, in a list of our friends the Invite button (to invite a friend) would no longer be appropriate as each of these users would already be a friend. The Delete button in this case would now be more appropriate. Clicking on the Invite button makes a call to the Redirector class and routes the user to the InviteFriends page. //UserControls/ProfileDisplay.ascx.cspublic void SendFriendRequest(Int32 AccountIdToInvite){ _redirector.GoToFriendsInviteFriends(AccountIdToInvite);}//Core/Impl/Redirector.cspublic void GoToFriendsInviteFriends(Int32 AccoundIdToInvite){ Redirect("~/Friends/InviteFriends.aspx?AccountIdToInvite=" + AccoundIdToInvite.ToString());} Inviting your friends This page allows us to manually enter email addresses of friends whom we want to invite. It is a standard From, To, Message format where the system specifies the sender (you), you specify who to send to and the message that you want to send. //Friends/InviteFriends.aspx<%@ Page Language="C#" MasterPageFile="~/SiteMaster.Master" AutoEventWireup="true" CodeBehind="InviteFriends.aspx.cs" Inherits="Fisharoo.FisharooWeb.Friends.InviteFriends" %><asp:Content ContentPlaceHolderID="Content" runat="server"> <div class="divContainer"> <div class="divContainerBox"> <div class="divContainerTitle">Invite Your Friends</div> <asp:Panel ID="pnlInvite" runat="server"> <div class="divContainerRow"> <div class="divContainerCellHeader">From:</div> <div class="divContainerCell"><asp:Label ID="lblFrom" runat="server"></asp:Label></div> </div> <div class="divContainerRow"> <div class="divContainerCellHeader">To:<br /><div class="divContainerHelpText">(use commas to<BR />separate emails)</div></div> <div class="divContainerCell"><asp:TextBox ID="txtTo" runat="server" TextMode="MultiLine" Columns="40" Rows="5"></asp:TextBox></div> </div> <div class="divContainerRow"> <div class="divContainerCellHeader">Message:</div> <div class="divContainerCell"><asp:TextBox ID="txtMessage" runat="server" TextMode="MultiLine" Columns="40" Rows="10"></asp:TextBox></div> </div> <div class="divContainerFooter"> <asp:Button ID="btnInvite" runat="server" Text="Invite" OnClick="btnInvite_Click" /> </div> </asp:Panel> <div class="divContainerRow"> <div class="divContainerCell"><br /><asp:Label ID="lblMessage" runat="server"> </asp:Label><br /><br /></div> </div> </div> </div></asp:Content> Running the code will display the following: This is a simple page, so the majority of the code for it is MVP plumbing. The most important part to notice here is that when the Invite button is clicked the presenter is notified to send the invitation. //Friends/InviteFriends.aspx.csusing System;using System.Collections;using System.Configuration;using System.Data;using System.Linq;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.HtmlControls;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Xml.Linq;using Fisharoo.FisharooWeb.Friends.Interface;using Fisharoo.FisharooWeb.Friends.Presenter;namespace Fisharoo.FisharooWeb.Friends{ public partial class InviteFriends : System.Web.UI.Page, IInviteFriends { private InviteFriendsPresenter _presenter; protected void Page_Load(object sender, EventArgs e) { _presenter = new InviteFriendsPresenter(); _presenter.Init(this); } protected void btnInvite_Click(object sender, EventArgs e) { _presenter.SendInvitation(txtTo.Text,txtMessage.Text); } public void DisplayToData(string To) { lblFrom.Text = To; } public void TogglePnlInvite(bool IsVisible) { pnlInvite.Visible = IsVisible; } public void ShowMessage(string Message) { lblMessage.Text = Message; } public void ResetUI() { txtMessage.Text = ""; txtTo.Text = ""; } }} Once this call is made we leap across to the presenter (more plumbing!). //Friends/Presenter/InviteFriendsPresenter.csusing System;using System.Data;using System.Configuration;using System.Linq;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.HtmlControls;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Xml.Linq;using Fisharoo.FisharooCore.Core;using Fisharoo.FisharooCore.Core.DataAccess;using Fisharoo.FisharooCore.Core.Domain;using Fisharoo.FisharooWeb.Friends.Interface;using StructureMap;namespace Fisharoo.FisharooWeb.Friends.Presenter{ public class InviteFriendsPresenter { private IInviteFriends _view; private IUserSession _userSession; private IEmail _email; private IFriendInvitationRepository _friendInvitationRepository; private IAccountRepository _accountRepository; private IWebContext _webContext; private Account _account; private Account _accountToInvite; public void Init(IInviteFriends view) { _view = view; _userSession = ObjectFactory.GetInstance<IUserSession>(); _email = ObjectFactory.GetInstance<IEmail>(); _friendInvitationRepository = ObjectFactory.GetInstance< IFriendInvitationRepository>(); _accountRepository = ObjectFactory.GetInstance<IAccountRepository>(); _webContext = ObjectFactory.GetInstance<IWebContext>(); _account = _userSession.CurrentUser; if (_account != null) { _view.DisplayToData(_account.FirstName + " " + _account.LastName + " &lt;" + _account.Email + "&gt;"); if (_webContext.AccoundIdToInvite > 0) { _accountToInvite = _accountRepository.GetAccountByID (_webContext.AccoundIdToInvite); if (_accountToInvite != null) { SendInvitation(_accountToInvite.Email, _account.FirstName + " " + _account.LastName + " would like to be your friend!"); _view.ShowMessage(_accountToInvite.Username + " has been sent a friend request!"); _view.TogglePnlInvite(false); } } } } public void SendInvitation(string ToEmailArray, string Message) { string resultMessage = "Invitations sent to the following recipients:<BR>"; resultMessage += _email.SendInvitations (_userSession.CurrentUser,ToEmailArray, Message); _view.ShowMessage(resultMessage); _view.ResetUI(); } }} The interesting thing here is the SendInvitation() method, which takes in a comma delimited array of emails and the message to be sent in the invitation. It then makes a call to the Email.SendInvitations() method. //Core/Impl/Email.cspublic string SendInvitations(Account sender, string ToEmailArray, string Message){ string resultMessage = Message; foreach (string s in ToEmailArray.Split(',')) { FriendInvitation friendInvitation = new FriendInvitation(); friendInvitation.AccountID = sender.AccountID; friendInvitation.Email = s; friendInvitation.GUID = Guid.NewGuid(); friendInvitation.BecameAccountID = 0; _friendInvitationRepository.SaveFriendInvitation(friendInvitation); //add alert to existing users alerts Account account = _accountRepository.GetAccountByEmail(s); if(account != null) { _alertService.AddFriendRequestAlert(_userSession.CurrentUser, account, friendInvitation.GUID, Message); } //TODO: MESSAGING - if this email is already in our system add a message through messaging system //if(email in system) //{ // add message to messaging system //} //else //{ // send email SendFriendInvitation(s, sender.FirstName, sender.LastName, friendInvitation.GUID.ToString(), Message); //} resultMessage += "• " + s + "<BR>"; } return resultMessage;} This method is responsible for parsing out all the emails, creating a new FriendInvitation, and sending the request via email to the person who was invited. It then adds an alert to the invited user if they have an Account. And finally we have to add a notification to the messaging system once it is built. Outlook CSV importer The Import Contacts page is responsible for allowing our users to upload an exported contacts file from MS Outlook into our system. Once they have imported their contacts, the user is allowed to select which email addresses are actually invited into our system. Importing contacts As this page is made up of a couple of views, let's begin with the initial view. //Friends/OutlookCsvImporter.aspx<asp:Panel ID="pnlUpload" runat="server"> <div class="divContainerTitle">Import Contacts</div> <div class="divContainerRow"> <div class="divContainerCellHeader">Contacts File:</div> <div class="divContainerCell"><asp:FileUpload ID="fuContacts" runat="server" /></div> </div> <div class="divContainerRow"> <div class="divContainerFooter"><asp:Button ID="btnUpload" Text="Upload & Preview Contacts" runat="server" OnClick="btnUpload_Click" /></div> </div> <br /><br /> <div class="divContainerRow"> <div class="divContainerTitle">How do I export my contacts from Outlook?</div> <div class="divContainerCell"> <ol> <li> Open Outlook </li> <li> In the File menu choose Import and Export </li> <li> Choose export to a file and click next </li> <li> Choose comma seperated values and click next </li> <li> Select your contacts and click next </li> <li> Browse to the location you want to save your contacts file </li> <li> Click finish </li> </ol> </div> </div></asp:Panel> As you can see from the code we are working in panels here. This panel is responsible for allowing a user to upload their Contacts CSV File. It also gives some directions to the user as to how to go about exporting contacts from Outlook. This view has a file upload box that allows the user to browse for their CSV file, and a button to tell us when they are ready for the upload. There is a method in our presenter that handles the button click from the view. //Friends/Presenter/OutlookCsvImporterPresenter.cspublic void ParseEmails(HttpPostedFile file){ using (Stream s = file.InputStream) { StreamReader sr = new StreamReader(s); string contacts = sr.ReadToEnd(); _view.ShowParsedEmail(_email.ParseEmailsFromText(contacts)); }} This method is responsible for handling the upload process of the HttpPostedFile. It puts the file reference into a StreamReader and then reads the stream into a string variable named contacts. Once we have the entire list of contacts we can then call into our Email class and parse all the emails out. //Core/Impl/Email.cspublic List<string> ParseEmailsFromText(string text){ List<string> emails = new List<string>(); string strRegex = @"w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*"; Regex re = new Regex(strRegex, RegexOptions.Multiline); foreach (Match m in re.Matches(text)) { string email = m.ToString(); if(!emails.Contains(email)) emails.Add(email); } return emails;} This method expects a string that contains some email addresses that we want to parse. It then parses the emails using a regular expression (which we won't go into details about!). We then iterate through all the matches in the Regex and add the found email addresses to our list provided they aren't already present. Once we have found all the email addresses, we will return the list of unique email addresses. The presenter then passes that list of parsed emails to the view. Selecting contacts Once we have handled the upload process and parsed out the emails, we then need to display all the emails to the user so that they can select which ones they want to invite. Now you could do several sneaky things here. Technically the user has uploaded all of their email addresses to you. You have them. You could store them. You could invite every single address regardless of what the user wants. And while this might benefit your community over the short run, your users would eventually find out about your sneaky practice and your community would start to dwindle. Don't take advantage of your user's trust! //Friends/OutlookCsvImporter.aspx<asp:Panel visible="false" ID="pnlEmails" runat="server"> <div class="divContainerTitle">Select Contacts</div> <div class="divContainerFooter"><asp:Button ID="btnInviteContacts1" runat="server" OnClick="btnInviteContacts_Click" Text="Invite Selected Contacts" /></div> <div class="divContainerCell" style="text-align:left;"> <asp:CheckBoxList ID="cblEmails" RepeatColumns="2" runat="server"></asp:CheckBoxList> </div> <div class="divContainerFooter"><asp:Button ID="btnInviteContacts2" runat="server" OnClick="btnInviteContacts_Click" Text="Invite Selected Contacts" /></div></asp:Panel> Notice that we have a checkbox list in our panel. This checkbox list is bound to the returned list of email addresses. public void ShowParsedEmail(List<string> Emails){ pnlUpload.Visible = false; pnlResult.Visible = false; pnlEmails.Visible = true; cblEmails.DataSource = Emails; cblEmails.DataBind();} The output so far looks like this: Now the user has a list of all the email addresses that they uploaded, which they can then go through selecting the ones that they want to invite into our system. Once they are through selecting the emails that they want to invite, they can click on the Invite button. We then iterate through all the items in the checkbox list to locate the selected items. protected void btnInviteContacts_Click(object sender, EventArgs e){ string emails = ""; foreach (ListItem li in cblEmails.Items) { if(li != null && li.Selected) emails += li.Text + ","; } emails = emails.Substring(0, emails.Length - 1); _presenter.InviteContacts(emails);} Once we have gathered all the selected emails, we pass them to the presenter to run the invitation process. public void InviteContacts(string ToEmailArray){ string result = _email.SendInvitations(_userSession.CurrentUser, ToEmailArray, ""); _view.ShowInvitationResult(result);} The presenter promptly passes the selected items to the Email class to handle the invitations. This is the same method that we used in the last section to invite users. //Core/Impl/Email.cspublic string SendInvitations(Account sender, string ToEmailArray, string Message){...} We then output the result of the emails that we invited into the third display. <asp:Panel ID="pnlResult" runat="server" Visible="false"> <div class="divContainerTitle">Invitations Sent!</div> <div class="divContainerCell"> Invitations were sent to the following emails:<br /> <asp:Label ID="lblMessage" runat="server"></asp:Label> </div></asp:Panel>
Read more
  • 0
  • 0
  • 4768

article-image-developing-simple-workflow-within-sugarcrm
Packt
22 Oct 2009
4 min read
Save for later

Developing a Simple Workflow within SugarCRM

Packt
22 Oct 2009
4 min read
A Very Simple Workflow In our simple workflow we'll assume that each task is carried out by one person at a time, and that all tasks are done sequentially (i.e. none are done in parallel). So, we'll look at the PPI Preliminary Investigation which, as you remember, maps to the standard SugarCRM Opportunity. Also, in this example, we're going to have a different person carrying out each one of the Investigation stages. Setting up the Process Stages If you look at SugarCRM then you'll see that by default none of the stages are related to investigations—they're all named using standard CRM terms: Obviously the first thing to do is to decide what the preliminary investigation stages actually are, and then map these to the SugarCRM stages. You'll realize that you'll need to edit the custom/include/langauge/en_us.lang.php file: $app_list_strings['sales_stage_dom']=array ( 'Prospecting' => 'Fact Gathering', 'Qualification' => 'Witness and Subject Location', 'Needs Analysis' => 'Witness and Subject Interviews', 'Value Proposition' => 'Scene Investigation', 'Id. Decision Makers' => 'Financial and background Investigation', 'Perception Analysis' => 'Document and evidence retrieval', 'Proposal/Price Quote' => 'Covert Camera surveillance', 'Negotiation/Review' => 'Wiretapping', 'Closed Won' => 'Full Investigation required', 'Closed Lost' => 'Insufficient Evidence',); Don't forget that you can also do this via Studio. However, once you've added your mapping into custom/include/langauge/en_us.lang.php file, and refresh your browser, then you'll see the new stages: Now that our stages are set up we need to know who'll be carrying out each one. Deciding Who Does What In our simple workflow there may not be the need to do anything further. Each person just needs to know who does what next: For example, once Kurt finishes the 'Covert Camera surveillance' stage then he just needs to update the Preliminary Investigation so that the stage is set to 'Wiretapping' and the assigned user as 'dobbsm'. However, things are rarely as simple as that. It's much more likely that: Investigations may be based on geographical locations, so that the above table may only apply to investigations based in London. Investigations based in New York follow the same process but with a different set of staff. On Mondays Fran does 'Witness and Subject Location' and William does 'Fact Gathering'. This means, of course, that we need to be using some businesses rules. Introducing Business Rules There are six 'triggers' that will cause the logic hooks to fire: after_retrieve before_save before_delete after_delete before_undelete after_undelete And the logic hooks are stored in custom/modules/<module name>/logic_hook.php, so for 'Preliminary Inquiries' this will be custom/modules/Opportunities/logic_hook.php. You'll also remember, of course, that the logic hook file needs to contain: The priority of the business rule The name of the businesses rule The file containing the business rule The business rule class The business rule function So, custom/modules/Opportunities/logic_hook.php needs to contain something like: <?php#As always ensure that the file can only be accessed through SugarCRMif(!defined('sugarEntry') || !sugarEntry) die( 'Not A Valid Entry Point');$hook_array = Array(); #Create an array$hook_array['before_save'] = Array();$hook_array['before_save'][] = Array(1, 'ppi_workflow', 'custom/include/ppi_workflow.php', 'ppi_workflow', 'ppi_workflow');?> Next we'll need the file that logic hook will be calling, but to start with this can be very basic—so, custom/include/ppi_workflow.php just needs to contain something like: <?php#Define the entry pointif(!defined('sugarEntry') || !sugarEntry) die( 'Not A Valid Entry Point');#Load any required filesrequire_once('data/SugarBean.php');require_once('modules/Opportunities/Opportunity.php');#Define the classclass ppi_workflow{ function ppi_workflow (&$bean, $event, $arguments) { }}?> With those two files set up as above nothing obvious will change in the operation of SugarCRM—the logic hook will fire, but we haven't told it to do anything, and so that what we'll do now. When the logic hook does run (i.e. when any Primary Investigation is saved) we would want it to: Check to see what stage we're now at Define the assigned user accordingly  
Read more
  • 0
  • 0
  • 4067

article-image-coldfusion-8-enhancements-you-may-have-missed
Packt
22 Oct 2009
5 min read
Save for later

ColdFusion 8-Enhancements You May Have Missed

Packt
22 Oct 2009
5 min read
<cfscript> Enhancements Poor <cfscript>! It can't be easy being the younger sibling to CFML tags. Natively, you can just do more with tags. Tags are arguably easier to learn and read, especially for beginners. Yet, since its introduction in ColdFusion 4.0, <cfscript> has dutifully done its job while getting none, or little, of the love. Given that ColdFusion was marketed as an easy-to-learn tag-based language that could be adopted by non-programmers who were only familiar with HTML, why did Allaire make the effort to introduce <cfscript>? Perhaps it was an effort to add a sense of legitimacy for those who didn't view a tag-based language as a true language. Perhaps it was a matter of trying to appeal to more seasoned developers as well as beginners. In either case, <cfscript> <cfscript> wasn't without some serious limitations that prevented it from gaining widespread acceptance.<cfscript> For example, while it boasted an ECMAScript-like syntax, which perhaps would have made it attractive to JavaScript developers, it was tied tightly enough to CFML that it used CFML operators. If you were used to writing the following to loop over an array in JavaScript: for (var i=0; i<myArray.length; i++) { … it wasn't quite a natural progression to write the same loop in cfscript<cfscript>: <cfscript>for (i=1; i lt arrayLen(myArray); i=i+1) {<cfscript> On the surface, it may look similar enough. But there are a few significant differences. First, the use of "lt" to represent the traditional "<" ('less than' operator). Second, the lack of a built-in increment operator. While ColdFusion does have a built-in incrementValue() function, that doesn't really do much to bridge the gap between <cfscript> and ECMAScript. When you're used to using traditional comparison operators in a scripting language (<, =, >, etc), as well as using increment operators (++), you would likely end up losing more time than you'd save in <cfscript>. Why? Because chances are that you'd type out the loop using the traditional comparison operators, run your code, see the error, smack your forehead, modify the code, and repeat. Well, your forehead is going to love this. As of ColdFusion 8, cfscript supports all of the traditional comparison operators (<, <=, ==, !=, =>, >). In addition, both <cfscript> and CFML support the following operators as of ColdFusion 8: Operator Name ColdFusion Pre CF 8 ColdFusion 8 ++ Increment i=i+1 i++ -- Decrement i=i-1 i-- % Modulus x = a mod b x = a%b += Compound Addition x = x + y x += y -= Compound Subtraction x = x - y x -= y *= Compound Multiplication x = x * y x *= y /= Compound Division x = x / y x /= y %= Compound Modulus x = x mod y x %= y &= Compound Concatenation (Strings) str = "abc"; str = str & "def"; str = "abc"; str &= "def"; && Logical And if (x eq 1) and (y eq 2) if (x == 1) && (y == 2) || Logical Or if (x eq 1) or (y eq 2) if (x == 1) || (y == 2) ! Logical Complement if (x neq y) if (! x == y)   For people who bounce back and forth between ColdFusion and languages like JavaScript or ActionScript, this should make the transitions significantly less jarring. Array and Structure Enhancements Arrays and structures are powerful constructs within the world of programming. While the naming conventions may be different, they exist in virtually every language. Creating even a moderately complex application without them would be an unpleasant experience to say the least. Hopefully you're already putting them to use. If you are, your life just got a little bit easier. Creating Arrays One of the perceived drawbacks to a tag-based language like CFML is that it can be a bit verbose. Consider the relatively straightforward task of creating an array and populating it with a small amount of data: <cfset myArray  = arrayNew(1) /><cfset myArray[1] = "Moe" /><cfset myArray[2] = "Larry" /><cfset myArray[3] = "Curly" /> In <cfscript> it gets a little bit better by cutting out some of the redundancy of the <cfset> <cfset> tags: <cfset&gt<cfscript> myArray  = arrayNew(1); myArray[1] = "Moe"; myArray[2] = "Larry"; myArray[3] = "Curly";</cfscript></cfset&gt A little bit better. But if you're familiar with languages like JavaScript, ActionScript, Java, or others, you know that this can still be improved upon. That's exactly what Adobe's done with ColdFusion 8. ColdFusion 8 introduces shorthand notation for the creation of arrays. <cfset myArray = [] /> The code above will create an empty array. In and of itself, this doesn't seem like a tremendous time saver. But, what if you could create the array and populate it at the same time? <cfset myArray = ["Larry", "Moe", "Curly"] /> The square brackets tell ColdFusion that you're creating an array. Inside the square brackets, a comma-delimited list populates the array. One caveat to be aware of is that ColdFusion has never taken much of a liking to empty list elements. The following will throw an error: <cfset myArray = ["Larry", , "Curly"] /> <!-- don't do this --> If you're populating your array dynamically, take steps to ensure that there are no empty elements in the list.      
Read more
  • 0
  • 0
  • 2419

article-image-creating-accessible-tables-joomla
Packt
22 Oct 2009
5 min read
Save for later

Creating Accessible Tables in Joomla!

Packt
22 Oct 2009
5 min read
Creating Accessible Tables Tables got a bad review in accessibility circles, because they used to create complex visual layouts. This was due to the limitations in the support for presentational specifications like CSS and using tables for layout was a hack—that worked in the real world—when you wanted to position something in a precise part of the web page. Tables were designed to present data of all shapes and sizes, and that is really what they should be used for. The Trouble with Tables So what are tables like for screen reader users? Tables often contain a lot of information, so sighted users need to look at the information at the top of the table (the header info), and sometimes the first column in each row to associate each data cell. Obviously this works for sighted users, but in order to make the tables accessible to a screen reader user we need to find a way of associating the data in each cell with its correct header so the screen reader can inform the user which header relates to each data cell. Screen reader users can navigate between data cells easily using the cursor keys. We will see how to make tables accessible in simple steps. There are methods of conveying the meaning and purpose of a table to the screen reader user by using the caption element and the summary attribute of the table element that you will find more on in the next section. We will learn how to build a simple table using Joomla! and the features contained within the WYSIWYG editors that can make the table more accessible. Before we do that though I want you to ask yourself about why you want to use tables (though sometimes it is unavoidable) and what forms should they take. Simple guidelines for tables: Try to make the table as simple as possible.    If possible don't span multiple cells etc. The simpler the table, the easier it is to make accessible.    Try to include the data you want to present in the body text of your site. Time for Action—Create an Accessible Table (Part 1) In the following example we will build a simple table that will list the names of some artists, some albums they have recorded, and the year in which they recorded the albums. First of all click the table icon from the TinyMCE interface and add a table with a suitable number of columns and rows.            By clicking on the Advanced tab you will see the Summary field. The summary information is very important. It provides the screen reader user a summary of the table. For example, I filled in the following text: "A list of some funk artists, my favorite among their records, and the year they recorded it in". My table then looked as follows: What Just Happened? There is still some work to be done in order to make the content more accessible. The controls that the WYSIWYG editor offers are also a little limited so we will have to edit the HTML by hand. Adding the summary information is a very good start. The text that I entered "A list of some funk artists, my favorite among their records, and the year they recorded it in." will be read out by the screen reader as soon as it receives a focus by the user. Time for Action—Create an Accessible Table (Part 2) Next we are going to add a Caption to the table, which will be helpful to both sighted and non-sighted users. This is how it's done. Firstly, select the top row of the table, as these items are the table heading. Then click on the Table Row properties icon beside the Tables icon and select Table Head under General Properties. Make sure that the Update current Row is selected in the dialogue box in the bottom left. You will apply these properties to your selected row. If you wish to add a caption to your table you need to add an extra row to the table and then select the contents of that row and add the Caption in the row properties dialogue box. This will tell the browser to display the caption text, in this case Funky Table Caption, else it will remain hidden. What Just Happened? By adding caption to the table, you provide useful information to the screen reader user. This caption should be informative and should describe something useful about the table. As the caption element is wrapped in a heading it is read out by the screen reader when the user starts exploring the table—so it is slightly different to the summary attribute, which is read out automatically. Does it Work? What we just did using the WYSIWYG editor, TinyMCE, is enough to make a good start towards creating a more accessible table, but we will have to work a little more in order to truly make the table accessible. So we will now edit the HTML. The good news is that you have made some good steps in the right direction and the final step is of associating the data cells with their suitable headers, as this is something that we cannot really do with the WYSIWYG editor alone, and is essential to make your tables truly accessible.
Read more
  • 0
  • 0
  • 2244

article-image-obtaining-alfresco-web-content-management-wcm
Packt
22 Oct 2009
11 min read
Save for later

Obtaining Alfresco Web Content Management (WCM)

Packt
22 Oct 2009
11 min read
You must obtain and install an additional download to enable Alfresco WCM functionality. The download includes a new Spring bean configuration file, a standalone Tomcat instance pre-configured with JARs, and server settings that allow a separate Tomcat instance (which is called the virtualization server) to run web applications stored in Alfresco WCM web folders. This capability is used when content managers "preview" an asset or a website. Just as in the core Alfresco server, you can either build the WCM distribution from source or obtain a binary distribution. Step-by-Step: Installing Alfresco WCM If you are building from source, the source code for Alfresco WCM is included with the source code for the rest of the product. Once the source code is checked out, all you have to do is run the distribute Ant task as follows: ant -f continuous.xml distribute After several minutes, the WCM distribution will be placed in the build|dist directory of your source code's root directory. Alternatively, if you are using binaries, download the binary distribution of the Alfresco WCM extension. Where you get it depends on whether you are running Labs or Enterprise. The Labs version is available for download from http://www.alfresco.com. The Enterprise version can be downloaded from the customer or partner site using the credentials provided by your Alfresco representative. Regardless of whether you chose source or binary, you should now have an Alfresco WCM archive. For example, the Labs edition for Linux is named alfresco-labs-wcm-3b.tar.gz. To complete the installation, follow these steps: Expand the archive into any directory that makes sense to you. For example, on my machine I use |usr|local|bin|alfresco-labs-3.0-wcm. Copy the wcm-bootstrap-context.xml file to the Alfresco server's extension directory ($TOMCAT_HOME|shared|classes|alfresco|extension). Edit the startup script (virtual_alf.sh) to ensure that the APPSERVER variable is pointing to the virtual-tomcat directory in the location to which you expanded the archive. Using the example from the previous step, the APPSERVER variable would be: APPSERVER=|usr|local|bin|alfresco-labs-3.0-wcm|virtual-tomcat Start the virtual server by running: |virtual_alf.sh start</i> Start the Alfresco server (or restart it if it was already running). You now have Alfresco with Alfresco WCM up and running. You'll test it out in the next section, but you can do a smoke test by logging in to the web client and confirming that you see the Web Projects folder under Company Home. Creating Web Projects A web project is a collection of assets, settings, and deployment targets that make up a website or a part of a website. Web projects are stored in web project folders, which are regular folders with a bunch of web project metadata. The number of web project folders you use to represent a site, or whether multiple sites are contained within a single web project folder is completely up to you. There is no "right way" that works for everybody. Permissions are one factor. The ability to set permissions stops at the website. Therefore, if you have multiple groups that maintain a site that are concerned with the ability of one to change the other's files, your only remedy is to split the site across web project folders. Web form and workflow sharing is another thing to think about. As you'll soon learn, workflows and web forms are defined globally, and then selectively chosen and configured by each site. Once made available to a web project, they are available to the entire web project. For example, you can't restrict the use of a web form to only a subset of the users of a particular site. SomeCo has chosen the approach of using one web project folder to manage the entire SomeCo.com website. Step-by-Step: Creating the SomeCo Web Project The first thing you need to do is create a new web project folder for the SomeCo website. Initially, you don't need to worry about web forms, deployment targets, or workflows. The goal is simply to create the web project and import the contents of the website. To create the initial SomeCo web project, follow these steps: Log in as admin. Go to Web Projects under Company Home. Click Create, and then Create Web Project. Specify the name of the web project as SomeCo Corporate Site. Specify the DNS name as someco-site. Click Next for the remaining steps, taking all defaults. You'll come back later and configure some of these settings. On the summary page, click Finish. You now have a web project folder for the SomeCo corporate site. Click SomeCo Corporate Site. You should see one Staging Sandbox and one User Sandbox. Click the Browse Website button for the User Sandbox. Now you can import SomeCo's existing website into the web project folder. Click Create, and then Bulk Import. Navigate to the "web-site" project in your Eclipse workspace. Assuming you've already run Ant for this project, there should be a ZIP file in the build folder called someco-web-site.zip. Select the file. Alfresco will import the ZIP into your User Sandbox. What Just Happened You just created a new web project folder for SomeCo's corporate website. But upon creation of a web project folder, there is no website to manage. This is a big disappointment for some people. The most crestfallen are those who didn't realize that Alfresco is a "decoupled" content management system—it has no frontend framework and no "default" website like "coupled" content management systems such as Drupal. This will change in the 3.0 releases as Alfresco introduces its new set of clients. But for now, it's up to you to give Alfresco a website to manage. You just happened to have a start on the SomeCo website sitting in your Eclipse workspace. Alfresco knows how to import WAR and ZIP files, which is a convenient way to migrate the website into Alfresco for the first time. Because web project sandboxes are mountable via CIFS, simply copying the website into the sandbox via CIFS is another way to go. The difference between the two approaches is that the WAR/ZIP import can only happen once. The import action complains if an archive contains nodes that already exist in the repository. If you haven't already done so, take a look at the contents of your sandbox. You should see index.html in the root of your User Sandbox and a someco folder that contains additional folders for CSS, images, JavaScript, and so on. The HTML file in the root is the same index.html file you deployed to the Alfresco web application in order to implement the AJAX ratings widget. Click the preview icon. (Am I the only one who thinks it looks eerily similar to the Turkish nazar talisman used to ward off the "evil eye"?) You should see the index page in a new tab or window. The list of Whitepapers won't be displayed. That's because the page is running in the context of the virtualization server, which is a different domain than your Alfresco server. Therefore, it is subject to the cross-domain restriction, which will be addressed later. Playing Nicely in the Sandbox Go back to the root of your web project folder. The link in the breadcrumb trail is likely to be the fastest way to navigate back. Click the Browse Website link in the Staging Sandbox. It's empty. If you were to invite another user to this website, his/her sandbox would be empty as well. Sandboxes are used to isolate changes each content owner makes, while still providing him/her the full context of the website. The Staging Sandbox represents your live website. Or in source code control terms, it is the HEAD of your site. It is assumed that whatever is in the Staging Sandbox can be safely deployed to the live website at any time. It is currently empty because you have not yet submitted any content to staging. Let's go ahead and do that now. If you click the Modified Items link in the User Sandbox, you'll see the index.html file and the someco folder. You could submit these individually. But you want everything to go to staging, so click Submit All: Provide a label and a description such as initial population and click OK. It is safe to ignore the warning that a suitable workflow was not found. That's expected because you haven't configured a workflow for this web project yet. Now the files have been submitted to staging. Here are some things to notice: If you click the Preview Website link in the Staging Sandbox, you'll see the website just as you did in the User Sandbox earlier. If you browse the website in the Staging Sandbox, you'll see the same files currently shown when you browse the website in your User Sandbox. A snapshot of the site was automatically taken when the files were committed and is listed under Recent Snapshots: Inviting Users To get a feel for how sandboxes work, invite one or more users to the web project (Actions, Invite Web Project Users). The following table describes the out of the box web project roles:   WCM User Role Can do these things Content Contributor Create and submit new content; but cannot edit or delete existing content Content Reviewer Create, edit, and submit new content; but cannot delete existing content Content Collaborator See all sandboxes, but only have full control over their own Create, edit, and submit new content; but cannot delete existing content Edit web project settings Content Manager See and modify content in all sandboxes; exert full control over all content See and deploy snapshots and manage deployment reports Edit web project settings Invite new users to the web project Delete the web project and individual sandboxes You'll notice that each new user gets his/her own sandbox, and that the sandbox automatically contains everything that is currently in staging. If a user makes a change to his/her sandbox, it is only visible within their sandbox until they commit the change to staging. If this is done, everyone else sees the change immediately. Unlike some content management and source code control systems, there is no need for other users to do an "update" or a "get latest" to copy the latest changes from staging into their sandbox. It is important to note that Alfresco will not merge conflicts. When a user makes a change to a file in his/her sandbox, it will be locked in all other sandboxes to prevent conflicts. If you were to customize Alfresco to disable locking, the last change would win. Alfresco would not warn you of the conflict. The Alfresco admin user and any user with Content Manager Access can see (and work within) all User Sandboxes. Everyone else sees only their own sandboxes. Mounting Sandboxes via CIFS All sandboxes are individually mountable via CIFS. In fact, in staging, each snapshot is individually mountable. This gives content owners the flexibility to continue managing content in their sandbox using the tools they are familiar with. The procedure for mounting a sandbox is identical to that of mounting the regular repository via CIFS, except that you use "AVM" as the mount point instead of "Alfresco". One difference between mounting the AVM repository through CIFS and mounting the DM repository is that the AVM repository directory structure is more complicated. For example, the path to the root of admin's sandbox in the SomeCo site is: |someco-site--admin|HEAD|DATA|www|avm_webapps|ROOT The first part of the path, someco-site, is the DNS name you assigned when you set up the web project. The admin string indicates which User Sandbox we are looking at. If you wanted to mount to the Staging Sandbox, the first part of the path would be someco-site without --admin. The next part of the path, HEAD, specifies the latest-and-greatest version of the website. Alternatively, you could mount a specific snapshot like this: |someco-site--admin|VERSION|v2|DATA|www|avm_webapps|ROOT As you might expect, the normal permissions apply. Users who aren't able to see another user's sandbox in the web client won't be able to do so through CIFS.
Read more
  • 0
  • 0
  • 2307
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 $19.99/month. Cancel anytime
Packt
22 Oct 2009
6 min read
Save for later

Working with Rails – Setting up and connecting to a database

Packt
22 Oct 2009
6 min read
In this article, authors Elliot Smith and Rob Nichols explain the setup of a new Rails application and how to integrate it with other data sources. Specifically, this article focuses on turning the abstract data structure for Intranet into a Rails application. This requires a variety of concepts and tools, namely: The structure of a Rails application. Initializing an application using the rails command. Associating Rails with a database. The built-in utility scripts included with each application. Using migrations to maintain a database. Building models and validating them. Using the Rails console to manually test models. Automated testing of models using Test::Unit. Hosting a project in a Subversion repository. Importing data into the application using scripts. In this article, we'll focus on the first 3 concepts. The World According to Rails To understand how Rails applications work, it helps to get under its skin: find out what motivated its development, and the philosophy behind it. The first thing to grasp is that Rails is often referred to as opinionated software (see http://www.oreillynet.com/pub/a/network/2005/08/30/ruby-rails-davidheinemeier-hansson.html). It encapsulates an approach to web application development centered on good practice, emphasizing automation of common tasks and minimization of effort. Rails helps developers make good choices, and even removes the need to make choices where they are just distractions. How is this possible? It boils down to a couple of things: Use of a default design for applications-By making it easy to build applications using the Model-View-Controller (MVC) architecture, Rails encourages separation of an application's database layer, its control logic, and the user interface. Rails' implementation of the MVC pattern is the key to understanding the framework as a whole. Use of conventions instead of explicit configuration-By encouraging use of a standard directory layout and file naming conventions, Rails reduces the need to configure relationships between the elements of the MVC pattern. Code generators are used to great effect in Rails, making it easy to follow the conventions. We'll see each of these features in more detail in the next two sections. Model-View-Controller Architecture The original aim of the MVC pattern was to provide architecture to bridge the gap between human and computer models of data. Over time, MVC has evolved into an architecture which decouples components of an application, so that one component (e.g. the control logic) can be changed with minimal impact on the other components (e.g. the interface). Explaining MVC makes more sense in the context of "traditional" web applications. When using languages such as PHP or ASP, it is tempting to mix application logic with database-access code and HTML generation. (Ruby, itself, can also be used in this way to write CGI scripts.) To highlight how a traditional web application works, here's a pseudo-code example:     # define a file to save email addresses into    email_addresses_file = 'emails.txt'    # get the email_address variable from the querystring    email_address = querystring['email_address']    # CONTROLLER: switch action of the script based on whether    # email address has been supplied    if '' == email_address        # VIEW: generate HTML form to accept user input which        # posts back to this script        content = "<form method='post' action='" + self + "'>        <p>Email address: <input type='text' name='email_address'/></p>        <p><input type='submit' value='Save'/></p>        </form>"    else        # VIEW: generate HTML to confirm data submission        content = "<p>Your email address is " + email_address + "</p>"        # MODEL: persist data        if not file_exists(email_addresses_file)            create_file(email_addresses_file)        end if        write_to_file(email_addresses_file, email_address)    end if    print "<html><head><title>Email manager</title></head>    <body>" + content + "</body></html>" The highlighted comments indicate how the code can be mapped to elements of the MVC architecture: Model components handle an application's state. Typically, the model does this by putting data into some kind of a long-term storage (e.g. database, filesystem). Models also encapsulate business logic, such as data validation rules. Rails uses ActiveRecord as its model layer, enabling data handling in a variety of relational database back-ends.In the example script, the model role is performed by the section of code which saves the email address into a text file. View components generate the user interface (e.g. HTML, XML). Rails uses ActionView (part of the ActionPack library) to manage generation of views.The example script has sections of code to create an appropriate view, generating either an HTML form for the user to enter their email address, or a confirmation message acknowledging their input. The Controller orchestrates between the user and the model, retrieving data from the user's request and manipulating the model in response (e.g. creating objects, populating them with data, saving them to a database). In the case of Rails, ActionController (another part of the ActionPack library) is used to implement controllers. These controllers handle all requests from the user, talk to the model, and generate appropriate views.In the example script, the code which retrieves the submitted email address, is performing the controller role. A conditional statement is used to generate an appropriate response, dependent on whether an email address was supplied or not. In a traditional web application, the three broad classes of behavior described above are frequently mixed together. In a Rails application, these behaviors are separated out, so that a single layer of the application (the model, view, or controller) can be altered with minimal impact on the other layers. This gives a Rails application the right mix of modularity, fl exibility, and power. Next, we'll see another piece of what makes Rails so powerful: the idea of using conventions to create associations between models, views, and controllers. Once you can see how this works, the Rails implementation of MVC makes more sense: we'll return to that topic in the section Rails and MVC.
Read more
  • 0
  • 0
  • 3291

article-image-php-data-objects-error-handling
Packt
22 Oct 2009
11 min read
Save for later

PHP Data Objects: Error Handling

Packt
22 Oct 2009
11 min read
In this article, we will extend our application so that we can edit existing records as well as add new records. As we will deal with user input supplied via web forms, we have to take care of its validation. Also, we may add error handling so that we can react to non-standard situations and present the user with a friendly message. Before we proceed, let's briefly examine the sources of errors mentioned above and see what error handling strategy should be applied in each case. Our error handling strategy will use exceptions, so you should be familiar with them. If you are not, you can refer to Appendix A, which will introduce you to the new object-oriented features of PHP5. We have consciously chosen to use exceptions, even though PDO can be instructed not to use them, because there is one situation where they cannot be avoided. The PDO constructors always throw an exception when the database object cannot be created, so we may as well use exceptions as our main error‑trapping method throughout the code. Sources of Errors To create an error handling strategy, we should first analyze where errors can happen. Errors can happen on every call to the database, and although this is rather unlikely, we will look at this scenario. But before doing so, let's check each of the possible error sources and define a strategy for dealing with them. This can happen on a really busy server, which cannot handle any more incoming connections. For example, there may be a lengthy update running in the background. The outcome is that we are unable to get any data from the database, so we should do the following. If the PDO constructor fails, we present a page displaying a message, which says that the user's request could not be fulfilled at this time and that they should try again later. Of course, we should also log this error because it may require immediate attention. (A good idea would be emailing the database administrator about the error.) The problem with this error is that, while it usually manifests itself before a connection is established with the database (in a call to PDO constructor), there is a small risk that it can happen after the connection has been established (on a call to a method of the PDO or PDO Statement object when the database server is being shutdown). In this case, our reaction will be the same—present the user with an error message asking them to try again later. Improper Configuration of the Application This error can only occur when we move the application across servers where database access details differ; this may be when we are uploading from a development server to production server, where database setups differ. This is not an error that can happen during normal execution of the application, but care should be taken while uploading as this may interrupt the site's operation. If this error occurs, we can display another error message like: "This site is under maintenance". In this scenario, the site maintainer should react immediately, as without correcting, the connection string the application cannot normally operate. Improper Validation of User Input This is an error which is closely related to SQL injection vulnerability. Every developer of database-driven applications must undertake proper measures to validate and filter all user inputs. This error may lead to two major consequences: Either the query will fail due to malformed SQL (so that nothing particularly bad happens), or an SQL injection may occur and application security may be compromised. While their consequences differ, both these problems can be prevented in the same way. Let's consider the following scenario. We accept some numeric value from a form and insert it into the database. To keep our example simple, assume that we want to update a book's year of publication. To achieve this, we can create a form that has two fields: A hidden field containing the book's ID, and a text field to enter the year. We will skip implementation details here, and see how using a poorly designed script to process this form could lead to errors and put the whole system at risk. The form processing script will examine two request variables:$_REQUEST['book'], which holds the book's ID and $_REQUEST['year'], which holds the year of publication. If there is no validation of these values, the final code will look similar to this: $book = $_REQUEST['book'];$year = $_REQUEST['year'];$sql = "UPDATE books SET year=$year WHERE id=$book";$conn->query($sql); Let's see what happens if the user leaves the book field empty. The final SQL would then look like: UPDATE books SET year= WHERE id=1; This SQL is malformed and will lead to a syntax error. Therefore, we should ensure that both variables are holding numeric values. If they don't, we should redisplay the form with an error message. Now, let's see how an attacker might exploit this to delete the contents of the entire table. To achieve this, they could just enter the following into the year field: 2007; DELETE FROM books; This turns a single query into three queries: UPDATE books SET year=2007; DELETE FROM books; WHERE book=1; Of course, the third query is malformed, but the first and second will execute, and the database server will report an error. To counter this problem, we could use simple validation to ensure that the year field contains four digits. However, if we have text fields, which can contain arbitrary characters, the field's values must be escaped prior to creating the SQL. Inserting a Record with a Duplicate Primary Key or Unique Index Value This problem may happen when the application is inserting a record with duplicate values for the primary key or a unique index. For example, in our database of authors and books, we might want to prevent the user from entering the same book twice by mistake. To do this, we can create a unique index of the ISBN column of the books table. As every book has a unique ISBN, any attempt to insert the same ISBN will generate an error. We can trap this error and react accordingly, by displaying an error message asking the user to correct the ISBN or cancel its addition. Syntax Errors in SQL Statements This error may occur if we haven't properly tested the application. A good application must not contain these errors, and it is the responsibility of the development team to test every possible situation and check that every SQL statement performs without syntax errors. If this type of an error occurs, then we trap it with exceptions and display a fatal error message. The developers must correct the situation at once. Now that we have learned a bit about possible sources of errors, let's examine how PDO handles errors. Types of Error Handling in PDO By default, PDO uses the silent error handling mode. This means that any error that arises when calling methods of the PDO or PDOStatement classes go unreported. With this mode, one would have to call PDO::errorInfo(), PDO::errorCode(), PDOStatement::errorInfo(), or PDOStatement::errorCode(), every time an error occurred to see if it really did occur. Note that this mode is similar to traditional database access—usually, the code calls mysql_errno(),and mysql_error() (or equivalent functions for other database systems) after calling functions that could cause an error, after connecting to a database and after issuing a query. Another mode is the warning mode. Here, PDO will act identical to the traditional database access. Any error that happens during communication with the database would raise an E_WARNING error. Depending on the configuration, an error message could be displayed or logged into a file. Finally, PDO introduces a modern way of handling database connection errors—by using exceptions. Every failed call to any of the PDO or PDOStatement methods will throw an exception. As we have previously noted, PDO uses the silent mode, by default. To switch to a desired error handling mode, we have to specify it by calling PDO::setAttribute() method. Each of the error handling modes is specified by the following constants, which are defined in the PDO class: PDO::ERRMODE_SILENT – the silent strategy. PDO::ERRMODE_WARNING – the warning strategy. PDO::ERRMODE_EXCEPTION – use exceptions. To set the desired error handling mode, we have to set the PDO::ATTR_ERRMODE attribute in the following way: $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); To see how PDO throws an exception, edit the common.inc.php file by adding the above statement after the line #46. If you want to test what will happen when PDO throws an exception, change the connection string to specify a nonexistent database. Now point your browser to the books listing page. You should see an output similar to: This is PHP's default reaction to uncaught exceptions—they are regarded as fatal errors and program execution stops. The error message reveals the class of the exception, PDOException, the error description, and some debug information, including name and line number of the statement that threw the exception. Note that if you want to test SQLite, specifying a non-existent database may not work as the database will get created if it does not exist already. To see that it does work for SQLite, change the $connStr variable on line 10 so that there is an illegal character in the database name: $connStr = 'sqlite:/path/to/pdo*.db'; Refresh your browser and you should see something like this: As you can see, a message similar to the previous example is displayed, specifying the cause and the location of the error in the source code. Defining an Error Handling Function If we know that a certain statement or block of code can throw an exception, we should wrap that code within the try…catch block to prevent the default error message being displayed and present a user-friendly error page. But before we proceed, let's create a function that will render an error message and exit the application. As we will be calling it from different script files, the best place for this function is, of course, the common.inc.php file. Our function, called showError(), will do the following: Render a heading saying "Error". Render the error message. We will escape the text with the htmlspecialchars() function and process it with the nl2br() function so that we can display multi-line messages. (This function will convert all line break characters to tags.) Call the showFooter() function to close the opening and tags. The function will assume that the application has already called the showHeader() function. (Otherwise, we will end up with broken HTML.) We will also have to modify the block that creates the connection object in common.inc.php to catch the possible exception. With all these changes, the new version of common.inc.php will look like this: <?php/*** This is a common include file* PDO Library Management example application* @author Dennis Popel*/// DB connection string and username/password$connStr = 'mysql:host=localhost;dbname=pdo';$user = 'root';$pass = 'root';/*** This function will render the header on every page,* including the opening html tag,* the head section and the opening body tag.* It should be called before any output of the/*** This function will 'close' the body and html* tags opened by the showHeader() function*/function showFooter(){?></body></html><?php}/*** This function will display an error message, call the* showFooter() function and terminate the application* @param string $message the error message*/function showError($message){echo "<h2>Error</h2>";echo nl2br(htmlspecialchars($message));showFooter();exit();}// Create the connection objecttry{$conn = new PDO($connStr, $user, $pass);$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);}catch(PDOException $e){showHeader('Error');showError("Sorry, an error has occurred. Please try your requestlatern" . $e->getMessage());} As you can see, the newly created function is pretty straightforward. The more interesting part is the try…catch block that we use to trap the exception. Now with these modifications we can test how a real exception will get processed. To do that, make sure your connection string is wrong (so that it specifies wrong databasename for MySQL or contains invalid file name for SQLite). Point your browser to books.php and you should see the following window:
Read more
  • 0
  • 0
  • 6809

article-image-aggregate-services-servicemix-jbi-esb
Packt
22 Oct 2009
10 min read
Save for later

Aggregate Services in ServiceMix JBI ESB

Packt
22 Oct 2009
10 min read
EAI - The Broader Perspective No one should have (or will) ever dared to build a 'Single System' which will take care of the entire business requirements of an enterprise. Instead, we build few (or many) systems,and each of them takes care of a set of functionalities in a single Line of Business (LOB). There is absolutely nothing wrong here, but the need of the hour is that these systems have to exchange information and interoperate in many new ways which have not been foreseen earlier. Business grows, enterprise boundaries expands and mergers and acquisition are all norms of the day. If IT cannot scale up with these volatile environments, the failure is not far. Let me take a single, but not simple problem that today's Businesses and IT face - Duplicate Data. By Duplicate Data we mean data related to a single entity stored in multiple systems and storage mechanisms, that too in multiple formats and multiple content. I will take the 'Customer' entity as an example so that I can borrow the 'Single Customer View' (SCV) jargon to explain the problem. We gather customer information while he makes a web order entry or when he raises a complaint against the product or service purchased or when we raise a marketing campaign for a new product to be introduced or ... The list continues, and in each of these scenarios we make use of different systems to collect and store the same customer information. 'Same Customer' - is it same? Who can answer this question? Is there a Data Steward who can provide you with the SCV from amongst the many information silos existing in your Organization? To rephrase the question, does your organization at least have a 'Single View of Truth', if it doesn't have a 'Single Source of Truth'? Information locked away inside disparate, monolithic application silos has proven a stubborn obstacle in answering the queries business requires, impeding the opportunities of selling, not to mention cross-selling and up-selling. Yeah, it's time to cleanse and distill each customer's data into a single best-record view that can be used to improve source system data quality. For that, first we need to integrate the many source systems available. Today, companies are even acquiring just to get access to it's invaluable Customer information! This is just one of the highlights of the importance of integration to control Information Entropy in the otherwise complicated IT landscape. Figure 1. The 'Single Customer View' Dilemma So Integration is not an end, but a means to end a full list of problems faced by enterprises today. We have been doing integration for many years. There exist many platforms, technologies and frameworks doing the same thing. Built around that, we have multiple Integration Architectures too, amongst which, the Point to Pont, Hub and Spoke, and the Message Bus are common. Figure 2 represents these integration topologies. Figure 2. EAI Topologies Let us now look at the salient features of these topologies to see if we are self-sufficient or need something more. Point to Point In Point to Point, we define integration solutions for a pair of applications. Thus, we have two end points to be integrated. We can build protocol and/or format adaptors/transformers at one or either end. This is the easiest way to integrate, as long as the volume of integration is low. We normally use technology specific APIs like FTP, IIOP, Remoting or batch interfaces to realize integration. The advantage is that between these two points, we have tight coupling, since both ends have knowledge about their peers. The downside is that if there are 6 nodes (systems) to be interconnected, we need at least 30 separate channels for both forward and reverse transport. So think of a mid-sized Enterprise with some 1000 systems to integrate! Hub & Spoke Hub And Spoke Architecture is also called as the Message Broker. It provides a centralized hub (Broker) to which all applications are connected. Each application connects with the central hub through lightweight connectors. The lightweight connectors facilitate application integration with minimum or no changes to the existing applications. Message Transformation and Routing takes place within the Hub. The major drawback of the Hub and Spoke Architecture is that if the Hub fails, the entire Integration topology fails. Enterprise Message Bus An Enterprise Message Bus provides a common communication infrastructure which acts as a platform-neutral and language-neutral adaptor between applications. This communication infrastructure may include a Message Router and/or Publish-Subscribe channels. So applications interact each other through the message bus with the help of Request-Response queues. Sometimes the applications have to use adapters that handle scenarios like invoking CICS transactions. Such adapters may provide connectivity between the applications and the message bus using proprietary bus APIs and application APIs. Service Oriented Integration (SOI) Service Oriented Architecture (SOA) provides us with a set of principles, patterns and practices, to provide and consume services which are orchestrated using open standards so as to remove single vendor lock-into provide an agile infrastructure where services range from business definition to technical implementation. In SOA, we no longer deal with single format and single protocol, instead we accept the fact that heterogeneity exists between applications. And our architecture still needs to ensure interoperability and thus information exchange. To help us do integration in the SOA manner, we require a pluggable service infrastructure where providers, consumers, and middleware services can collaborate in the famous 'Publish -- Find -- Bind' triangle. So, similar to the integration topologies described above, we need a backbone upon which we can build SOA that can provide a collection of middleware services that provides integration capabilities. This is what we mean by Service Oriented Integration (SOI). Gartner originally identified Enterprise Service Bus (ESB) Architecture as a core component in the SOA landscape. ESB provides a technical framework to align your SOA based integration needs. In the rest of the article we will concentrate on ESB. Enterprise Service Bus (ESB) Roy Schutle from Gartner defines an ESB as:"A Web-services-capable middleware infrastructure that supports intelligent program-to-program communication and mediates the relationships among loosely-coupled and uncoupled business components." In the ESB Architecture (Refer Figure 2), applications communicate through an SOA middleware backbone. The most distinguishing feature of the ESB Architecture is the distributed nature of the integration topology. This makes the ESB capabilities to spread out across the bus in a distributed fashion, thus avoiding any single point of failure. Scalability is achieved by distributing the capabilities into separately deployable service containers. Smart, intelligent connectors connect the applications to the Bus. Technical services like transformation, routing, security, etc. are provided internally by these connectors. The Bus federates services which are hosted locally or remotely, thus collaborating distributed capabilities. Many ESB solutions are based on Web Services Description Language (WSDL) technologies, and they use Extensible Markup Language (XML) formats for message translation and transformation. The best way to think about an ESB is to imagine the many features which we can provide to the message exchange at a mediation layer (the ESB layer), a few among them is listed below: Addressing & Routing  Synchronous and Asynchronous style invocations  Multiple Transport and protocol bindings  Content transformation and translation  Business Process Orchestration (BPM)  Event processing  Adapters to multiple platforms  etc... Service Aggregation in ESB ESB provides you the best ways of integrating services so that services are not only interoperable but also reusable in the form of aggregating in multiple ways and scenarios. This means, services can be mixed and matched to adapt to multiple protocols and consumer requirements. Let me explain you this concept, as we will explore more into this with the help of sample code too. In code and component reuse, we try to reduce ‘copy and paste’ reuse and encourage inheritance, composition and instance pooling. Similar analogy exists in SOI where services are hosted and pooled for multiple clients through multiple transport channels, and ESB can do this in the best way integration world has ever seen. We call this as the notion of shared services. For example, if a financial organization provides a ‘credit history check service’, an ESB can facilitate reuse of this service by multiple business processes (like a Personal Loan approval process or a Home Mortgage approval process). So, once we create our 'core services', we can then arbitrarily compose these services in a declarative fashion so as to define and publish more and more composite services. Business Process Management (BPM) tools can be integrated over ESB to leverage service aggregation and service collaboration. This facilitates reuse of basic or core (or fine grained) services at Business Process level. So, granularity of services is important which will also decide the level of reusability. Coarse grained or composite services consume fine grained services. Applications that consume  coarse-grained services are not exposed to the fine-grained services they use. Composite services can be assembled from coarse-grained as well as fine-grained services. To make the concept clear, let us take the example of provisioning a new VOIP (Voice Over IP) Service for a new Customer. This is a composite service which in turn calls multiple coarse grained services like 'validateOrder', 'createOrVerifyCustomer', 'checkProductAvailability', etc. Now, the createOrVerifyCustomer coarse grained service in turn call multiple fine grained services like 'validateCustomer', 'createCustomer', 'createBillingAddress', 'createMailingAddress', etc. Figure 3. Service Composition Java Business Integration (JBI) Java Business Integration (JBI) provides a collaboration framework which provides standard interfaces for integration components and protocols to plug into, thus allowing the assembly of Service Oriented Integration (SOI) frameworks. JSR 208 is an extension of Java 2 Enterprise Edition (J2EE), but it is specific for Java Business Integration Service Provider Interfaces (SPI). SOA and SOI are the targets of JBI and hence it is built around Web Services Description Language (WSDL). The nerve of the JBI architecture is the NMR (Normalized Message Router). This is a bus through which messages flow in either directions from a source to a destination. You can listen to Ron Ten-Hove, the Co-spec lead for JSR 208 here and he writes more about JBI components in the PDF download titled JBI Components: Part 1. JBI provides the best available, open foundation for structuring applications by composition of services rather than modularized, structured code that we have been doing in traditional programming paradigms. A JBI compliant ESB implementation must support four different service invocations, leading to four corresponding Message Exchange Patterns (MEP):   One-Way (In-Only MEP): Service Consumer issues a request to Service Provider. No error (fault) path is provided.  Reliable One-Way (Robust In-Only MEP): Service Consumer issues a request to Service Provider. Provider may respond with a fault if it fails to process the request.  Request-Response (In-Out MEP): Service Consumer issues a request to Service Provider, with expectation of response. Provider may respond with a fault if it fails to process request.  Request Optional-Response (In Optional-Out MEP): Service Consumer issues a request to Service Provider, which may result in a response. Both Consumer and provider have the option of generating a fault in response to a message received during the interaction.
Read more
  • 0
  • 0
  • 4222

article-image-pop-image-widget-using-javascript-php-and-css
Packt
22 Oct 2009
7 min read
Save for later

Pop-up Image Widget using JavaScript, PHP and CSS

Packt
22 Oct 2009
7 min read
If you’re a regular blog reader then it’s likely that you’ve encountered the Recent Visitors widget form (http://mybloglog.com). This widget displays the profile like name, picture and sites authored by members of Mybloglog who have recently visited your blog. In the Mybloglog widget, when you move the mouse cursor to the member’s picture, you’ll see a popup displaying a brief description of that member. A glance at MyBlogLog widget The above image is of a MyBlogLog widget. As you can see in the right part of the widget, there is a list of the recent visitors to the blog from members of MyBlogLog. You may also have noticed that in the left part of the widget is a popup showing the details and an image of the visitor. This popup is displayed when the mouse is moved over the image on the widget. Now, let’s look at the code which we got from MyBlogLog to display the above widget. <script src="http://pub.mybloglog.com/comm3.php?mblID=2007121300465126&r= widget&is=small&o=l&ro=5&cs=black&ww=220&wc=multiple"></script> In the above script element, the language and type attributes are not specified. Although they are optional attributes in HTML - you must specify a value in the type attribute to make the above syntax valid in an XHTML web page. If you closely looked at the src attribute of the script element, you can see that the source page of the script is a .php file. You can use the JavaScript code with any file extension like .php , .asp, and so on , but whenever you use such a file in src attribute please note that the final output code of the file (after being parsed by server) should be a valid JavaScript code. Creating pop-up image widget This pop-up image widget is somewhat similar to MyBlogLog widget but it is a simplified version of that widget. This is a very simple widget with uses JavaScript, PHP and CSS. Here you’ll see four images in the widget and a pop-up image (corresponding to the chosen image) will be displayed when you move the mouse over it. After getting the core concept, you can extend the functionality to make this look fancier. Writing Code for Pop-up Image Widget As I’ve already discussed, this widget is going to contain PHP code, JavaScript and a little bit of CSS as well. For this, you need to write the code in a PHP file with the .php extension. First of all, declare the variables for storing the current mouse position and string variables for storing the string of the widget. var widget_posx=0;var widget_posy=0;var widget_html_css=''; The widget_posx variable is to hold the x co-ordinate values of the mouse position on the screen, whereas, the widget_posy variable will store the y co-ordinate. The widget_html_css variable stores the HTML and CSS elements which will be used later in the code. The (0,0) co-ordinate of the output devices like monitor is located at the top left position. So the mouse position 10,10 will be somewhere near the top left corner of monitor. After declaring the variables, let’s define an event handler to track the mouse position on the web page. document.onmousemove=captureMouse; As you can see above, we’ve called a function captureMouse() When the mouse is moved anywhere on the document (web page), the event handler which is the function captureMouse() is called on the onmousemove event. The Document object represents the entire HTML document and can be used to access and capture the events of all elements on a page. Each time a user moves the mouse one pixel, a mousemove event occurs. It engages system resources to process all mousemove events, hence, use this event carefully! Now, let’s look at the code of the captureMouse() function. function captureMouse(event){ if (!event){var event = window.event;}if (event.pageX || event.pageY) { widget_posx = event.pageX; widget_posy = event.pageY; } else if (event.clientX || event.clientY) { widget_posx = event.clientX; widget_posy = event.clientY; } } As you can see in the above function, the event variable is passed as a function parameter. This event variable is the JavaScript’s Event object. The Event object keeps track of various events that occur on the page, such as the user moving the mouse or clicking on the link, and allows you to react to them by writing code which is relevant to the event. if (!event){var event = window.event;} In the above code, the first line of the event handler ensures that if the browser doesn’t pass the event information to the above function, then we would obtain it from any explicit event registration of the window object. We can track different activity in the document by the event object with the help of its various defined properties. For example, if eventObj is the event object and we’ve to track whether the ctrl key is pressed (or not) - we can use the following code in JavaScript: eventObj.ctrlKey If we’ve assigned the x, y-position of mouse in the page using the pageX and pageY properties, we can also get the same mouse position of the mouse cursor using clientX and clientY property. Most browsers provide both pageX/pageY and clientX/clientY. Internet Explorer is the only current browser that provides clientX/clientY, but not pageX/pageY. To provide cross-browser support, we’ve used both pageX/pageY and clientX/clientY to get the mouse co-ordinates in the document, and assigned them to the widget_posx and widget_posy variables accordingly. Now, let’s look at widget_html_css variable, where we’re going to store the string which is going to be displayed in the widget. widget_html_css+='<style type="text/css">';widget_html_css+='.widgetImageCss';widget_html_css+='{ margin:2px;border:1px solid #CCCCCC;cursor:pointer}';widget_html_css+='</style>'; As you can see in the string of the above variable, we’ve added the style for the HTML element with the class name widgetImageCss within the style element. When applied, this class in the HTML adds a 2 pixel margins ‘brown color border’ to the element. Furthermore, the mouse cursor will be converted into pointer (a hand) which is defined with the cursor attribute in CSS. widget_html_css+='<div id="widget_popup"style="position:absolute;z-index:10; display:none">&nbsp;</div>'; Using the above code, we’re adding a division element with id widget_popup to the DOM. We’ve also added style to this element using inline styling. The position attribute of this element is set to absolute so that this element can move freely without disturbing the layout of the document. The z-index property is used for stacking the order of the element and in the above element it is set 10 so that this element will be displayed above all the other elements of the document. Finally, the display property is set to none for hiding the element at first. Afterwards, this element will be displayed with the pop-up image using JavaScript in the document. Elements can have negative stack orders i.e. you can set the z-index to -1 for an element. This will display it underneath the other elements on the page. Z-index only works on elements that have been positioned using CSS (such as position:absolute). Now, the PHP part of the codes comes in. We’ve used PHP to add the images to the widget_html_css string variables of JavaScript. We’ve used PHP in this part rather than using JavaScript for making this application flexible. JavaScript is a client side scripting language and can’t access the database or do any kind of server activity. Using PHP, you can extract and display the images from the database which might be the integral part of your desired widget.
Read more
  • 0
  • 0
  • 8547
article-image-customer-management-joomla-and-virtuemart
Packt
22 Oct 2009
7 min read
Save for later

Customer Management in Joomla! and VirtueMart

Packt
22 Oct 2009
7 min read
Note that all VirtueMart customers must be registered with Joomla!. However, not all Joomla! users need to be the VirtueMart customers. Within the first few sections of this article, you will have a clear concept about user management in Joomla! and VirtueMart. Customer management Customer management in VirtueMart includes registering customers to the VirtueMart shop, assigning them to user groups for appropriate permission levels, managing fields in the registration form, viewing and editing customer information, and managing the user groups. Let's dive in to these activities in the following sections. Registration/Authentication of customers Joomla! has a very strong user registration and authentication system. One core component in Joomla! is com_users, which manages user registration and authentication in Joomla!. However, VirtueMart needs some extra information for customers. VirtueMart collects this information through its own customer registration process, and stores the information in separate tables in the database. The extra information required by VirtueMart is stored in a table named jos_vm_user_info, which is related to the jos_users table by the user id field. Usually, when a user registers to the Joomla! site, they also register with VirtueMart. This depends on some global settings. In the following sections, we are going to learn how to enable the user registration and authentication for VirtueMart. Revisiting registration settings We configure the registration settings from VirtueMart's administration panel Admin | Configuration | Global screen. There is a section titled User Registration Settings, which defines how the user registration will be handled: Ensure that your VirtueMart shop has been configured as shown in the screenshot above. The first field to configure is the User Registration Type. Selecting Normal Account Creation in this field creates both a Joomla! and VirtueMart account during user registration. For our example shop, we will be using this setting. Joomla!'s new user activation should be disabled when we are using VirtueMart. That means the Joomla! New account activation necessary? field should read No. Enabling VirtueMart login module There is a default module in Joomla! which is used for user registrations and login. When we are using this default Login Form (mod_login module), it does not collect information required by VirtueMart, and does not create customers in VirtueMart. By default, when published, the mod_login module looks like the following screenshot: As you see, registered users can log in to Joomla! through this form, recover their forgotten password by clicking on the Forgot your password? link, and create a new user account by clicking on the Create an account link. When a user clicks on the Create an account link, they get the form as shown in the following screenshot: We see that normal registration in Joomla! only requires four pieces of information: Name, Username, Email, and Password. It does not collect information needed in VirtueMart, such as billing and shipping address, to be a customer. Therefore, we need to disable the mod_login module and enable the mod_virtuemart_login module. We have already learned how to enable and disable a module in Joomla!. We have also learned how to install modules. By default, the mod_virtuemart_login module's title is VirtueMart Login. You may prefer to show this title as Login only. In that case, click on the VirtueMart Login link in the Module Name column. This brings the Module:[Edit] screen: In the Title field, type Login (or any other text you want to show as the title of this module). Make sure the module is enabled and position is set to left or right. Click  on the Save icon to save your settings. Now, browse to your site's front-page  (for example, http://localhost/bdosn/), and you will see the login form as shown in the following screenshot: As you can see, this module has the same functionalities as we saw in the mod_login module of Joomla!. Let us test the account creation in this module. Click on the Register link. It brings the following screen: The registration form has three main sections: Customer Information, Bill To Information, and Send Registration. At the end, there is the Send Registration button for submitting the form data. In the Customer Information section, type your email address, the desired username, and password. Confirm the password by typing it again in the Confirm password field. In the Bill To Information section, type the address details where bills are to be sent. In the entire form, required fields are marked with an asterisk (*). You must provide information for these required fields. In the Send Registration section, you need to agree to the Terms of Service. Click on the Terms of Service link to read it. Then, check the I agree to the Terms of Service checkbox and click on the Send Registration button to submit the form data: If you have provided all of the required information and submitted a unique  email address, the registration will be successful. On successful completion of registration, you get the following screen notification, and will be logged in to  the shop automatically: If you scroll down to the Login module, you will see that you are logged in and greeted by the store. You also see the User Menu in this screen: Both the User Menu and the Login modules contain a Logout button. Click on either of these buttons to log out from the Joomla! site. In fact, links in the User Menu module are for Joomla! only. Let us try the link Your Details. Click on the Your Details link, and you will see the information shown in the following screenshot: As you see in the screenshot above, you can change your full name, email, password, frontend language, and time zone. You cannot view any information regarding billing address, or other information of the customer. In fact, this information is for regular Joomla! users. We can only get full customer information by clicking on the Account Maintenance link in the Login module. Let us try it. Click on the Account Maintenance link, and it shows the following screenshot: The Account Maintenance screen has three sections: Account Information, Shipping Information, and Order Information. Click on the Account Information link to see what happens. It shows the following screen: This shows Customer Information and Bill To Information, which have been entered during user registration. The last section on this screen is the Bank Information, from where the customer can add bank account information. This section looks like the following screenshot: As you can see, from the Bank Account Info section, the customers can enter their bank account information including the account holder's name, account number, bank's sorting code number, bank's name, account type, and IBAN (International Bank Account Number). Entering this information is important when you are using  a Bank Account Debit payment method. Now, let us go back to the Account Maintenance screen and see the other sections. Click on the Shipping Information link, and you get the following screen: There is one default shipping address, which is the same as the billing address. The customers can create additional shipping addresses. For creating a new shipping address, click on the Add Address link. It shows the following screen:
Read more
  • 0
  • 0
  • 11449

article-image-consuming-adapter-outside-biztalk-server
Packt
22 Oct 2009
3 min read
Save for later

Consuming the Adapter from outside BizTalk Server

Packt
22 Oct 2009
3 min read
In addition to infrastructure-related updates such as the aforementioned platform modernization, Windows Server 2008 Hyper-V virtualization support, and additional options for fail over clustering, BizTalk Server also includes new core functionality. You will find better EDI and AS2 capabilities for B2B situations and a new platform for mobile development of RFID solutions. One of the benefits of the new WCF SQL Server Adapter that I mentioned earlier was the capability to use this adapter outside of a BizTalk Server solution. Let's take a brief look at three options for using this adapter by itself and without BizTalk as a client or service. Called directly via WCF service reference If your service resides on a machine where the WCF SQL Server Adapter (and thus, the sqlBinding) is installed, then you may actually add a reference directly to the adapter endpoint. I have a command-line application, which serves as my service client. If we right-click this application, and have the WCF LOB Adapter SDK installed, then Add Adapter Service Reference appears as an option. Choosing this option opens our now-beloved wizard for browsing adapter metadata. As before, we add the necessary connection string details and browse the BatchMaster table and opt for the Select operation. Unlike the version of this wizard that opens for BizTalk Server projects, notice the Advanced options button at the bottom. This button opens a property window that lets us select a variety of options such as asynchronous messaging support and suppression of an accompanying configuration file. After the wizard is closed, we end up with a new endpoint and binding in our existing configuration file, and a .NET class containing the data and service contracts necessary to consume the service. We should now call this service as if we were calling any typical WCF service. Because the auto-generated namespace for the data type definition is a bit long, I first added an alias to that namespace. Next, I have a routine, which builds up the query message, executes the service, and prints a subset of the response. using DirectReference = schemas.microsoft.com.Sql._2008._05.Types.Tables.dbo; … private static void CallReferencedSqlAdapterService() { Console.WriteLine("Calling referenced adapter service");TableOp_dbo_BatchMasterClient client = new TableOp_dbo_BatchMasterClient("SqlAdapterBinding_TableOp_dbo_BatchMaster"); try{string columnString = "*";string queryString = "WHERE BatchID = 1";DirectReference.BatchMaster[] batchResult =client.Select(columnString, queryString);Console.WriteLine("Batch results ...");Console.WriteLine("Batch ID: " + batchResult[0].BatchID.ToString());Console.WriteLine("Product: " + batchResult[0].ProductName);Console.WriteLine("Manufacturing Stage: " + batchResult[0].ManufStage);client.Close(); Console.ReadLine(); } catch (System.ServiceModel.CommunicationException){client.Abort(); } catch (System.TimeoutException) { client.Abort(); } catch (System.Exception) { client.Abort(); throw; } } Once this quick block of code is executed, I can confirm that my database is accessed and my expected result set returned.
Read more
  • 0
  • 0
  • 1899

Packt
22 Oct 2009
7 min read
Save for later

Data Types in Microsoft® Dynamics™ NAV

Packt
22 Oct 2009
7 min read
As you know, design of an application starts with the data. The data design depends on the types of data that your development tool set allows you to use. Since NAV is designed specifically to develop financially oriented business applications, the NAV data types are financially and business oriented, and also have some special features that make it easier to design and develop typical business applications. Furthermore, these same special features can make your applications run faster. In this article, we will cover the data types that you are most likely to use. We will also take an overview of the others. In addition, we will also cover field classes, which are where the special features are enabled. Fields A field is the basic element of data definition in NAV—the "atom" in the structure of a system. The mechanical definition of a field consists of its number, its description (name), and its data type (and, of course, any parameters required for its particular data type). From a logical point of view, a field is also defined by its Properties and the C/AL code contained in its Triggers. Field Properties The specific properties that can be defined for a field partially depend on the data type. First we will review the universal field properties. Then we will review the properties that are data-type dependent plus some other field properties. You can check out the remaining properties by using Help within the Table Designer.Fields You can access the properties of a field while viewing the table in Design mode, by highlighting the field line whose properties you wish to examine and clicking on the Properties icon or pressing Shift + F4. All the property screenshots in this section are obtained in this way for fields within the standard Customer table. As we review various field properties, you will learn more if, using the Object Designer, you follow along in your NAV system. Poke around and explore different properties and the values they can have. Use the Field Help function liberally and read the help for various properties. The property value enclosed in < > (less than sign, greater than sign), is the default value for that property. When you set a property to any other value, < and > should not be present unless they are supposed to be the part of the property value (e.g. part of a Text string value).All data types have the following properties: Property Property Description Field No. Identifier for the field within the table object Name Label by which code references the field. The name can be changed at any time and NAV will automatically ripple that change throughout the code Caption and Caption ML Work similarly as named table properties Description Used for internal documentation only Data Type Identifies what kind of data format applies to this field (e.g. Integer, Date, Code, Text, etc.) Enabled Determines if the field is activated for data handling or not. This property defaults to yes and is rarely changed   The following screenshot shows the BLOB properties for the Picture Field in the Customer table: This set of properties, for fields of the BLOB data type, is the simplest set of field properties. After the properties that are shared by all data types, appear the BLOB-specific properties—SubType and Owner:    SubType: This defines the type of data stored in the BLOB. The three  sub-type choices are Bitmap (for bitmap graphics), Memo (for text data), and  User-Defined (for anything else). User-Defined is the default value.    Owner: The usage is not defined.   The available properties of Code and Text fields are quite similar to one another. The following are some common properties between the two as shown in the screenshot overleaf:   DataLength: This specifies how many characters long the data field is. InitValue: This is the value that the system should supply as a default when  the system actively initializes the field. AltSearchField: This allows definition of an alternative field in the same  table to be searched for a match if no match is found on a lookup on this datastyle="width: 761px; height: 446px;"  item. For example, you might want to allow customers to be looked up eitherstyle="width: 761px; height: 446px;"  by their Customer No. or by their Phone No. In that case, in the No. field  properties you would supply the Phone No. field name in the AltSearchField  field. Then, when a user searches in the No. field, NAV will first look for  a match in the No. field and, if it is not found there, it will then search  the Phone No. field for a match. Use of this property can save you a lot of  coding, but make sure both fields have high placement in a key so the lookup  will be speedy. Editable: This is set to No when you don't want to allow a field to ever be  edited for example, if this is a computed or assigned value field that the user  should not change. NotBlank, Numeric, CharAllowed, DateFormula, and ValuesAllowed: All  these support placing constraints on the specific data that can be entered into  this field. TableRelation and ValidateTableRelation: These are used to  control referencing and validation of entries against another table.  (TestTableRelation is an infrequently used property, which controls whether  or not this relationship should be tested during a database validation test.) Let us take a look at the properties of couple more Data types, Integer and Decimal. You may find it useful to explore them on your own as well. Specific properties related to the basic numeric content of these data types are as follows and are also shown in the following screenshot: DecimalPlaces: This sets the number of decimal places in a Decimal  data item. BlankNumbers, BlankZero, and SignDisplacement: All these can be used to  influence the formatting and display of the data in the field. MinValue and MaxValue: These can constrain the range of data values allowed. AutoIncrement: This allows setting up of one field in a table to automatically  increment for each record entered. This is almost always used to support  automatic updating of a field used as the last field in a primary key, enabling  creation of a unique key. The field properties for an Integer field with a FieldClass property of FlowField are similar to those of a field with a FieldClass property of Normal. The differencesstyle="width: 761px; height: 446px;"relate to the fact that the field does not actually contain data but holds the formula by which the displayed value is calculated, as shown in the following screenshot overleaf. Note the presence of the CalcFormula property and the absence of the AltSearchField, AutoIncrement, and TestTableRelation properties. Similar differences exist for FlowFields of other data types. The properties for an Option data type, whose properties are shown in the following screenshot, are essentially like those of the other numeric data types, but with a datatype-specific set of properties as described below: OptionString: This spells out the text interpretations for the stored integer  values contained in Option data type fields. OptionCaption and OptionCaptionML: These serve the same captioning  and multi-language purposes as other caption properties. The properties defined for FlowFilter fields, such as Date Filter in the following screenshot overleaf, are similar to those of Normal data fields. Take a look at the Date Filter field (a Date FlowFilter field) and the Global Dimension 1 Filter field (a Code FlowFilter field) in the Customer table. The Date Filter field property looks similar to a Normal FieldClass field.
Read more
  • 0
  • 0
  • 4613
article-image-languages-and-language-settings-moodle
Packt
22 Oct 2009
7 min read
Save for later

Languages and Language Settings in Moodle

Packt
22 Oct 2009
7 min read
Language The default Moodle installation includes many Language packs. A language pack is a set of translations for the Moodle interface. Language packs translate the Moodle interface, and not the course content. Here's the Front Page of a site when the user selects Spanish from the language menu: Note that every aspect of the interface is being presented in Spanish: menu names, menu items, section names, buttons, and system messages. Now, let's take a look at the same Front Page when the user selects Romanian from the language menu: Note that much of the interface has not been translated. For example, the Site Administration menu and section name for Site news are still in English. When a part of Moodle's interface is not translated into the selected language, Moodle uses the English version. Language Files When you install an additional language, Moodle places the language pack in its data directory under the subdirectory /lang. It creates a subdirectory for each language files. The following screenshot shows the results of installing the International Spanish and Romanian languages: For example, the subdirectory, /lang/en_us, holds files for the U.S. English translation, and /lang/es_es holds the files for traditional Spanish (Espanol / Espana). The name of the subdirectory is the 'language code'. Knowing this code will come in handy later. In the previous example, es_utf8 tells us that the language code for International Spanish is es. Inside a language pack's directory, we see a list of files that contain the translations: For example, the /lang/es_utf8/forum.php file holds text used on the forum pages. Let us suppose that we are creating a course for students. This file would include the text that is displayed to the course creator while creating the forum, and the text that is displayed to the students when they use the forum. Here are the first few lines from the English version of that file: $string['addanewdiscussion'] = 'Add a new discussion topic';$string['addanewtopic'] = 'Add a new topic';$string['advancedsearch'] = 'Advanced search'; And here are the same first three lines from the Spanish version of that file: $string['addanewdiscussion'] = 'Colocar un nuevo tema de discusión aquí';$string['addanewtopic'] = 'Agregar un nuevo tema';$string['advancedsearch'] = 'Búsqueda avanzada'; The biggest task in localizing Moodle consists of translating these language files into the appropriate languages. Some translations are surprisingly complete. For example, most of the interface has been translated to Irish Gaelic, even though this language is used by only about 350,000 people everyday. The Romanian interface remains mostly untranslated although Romania has a population of over 23 million. This means that if a Moodle user chooses the Romanian language (ro), most of the interface will still default to English. Language Settings You access the Language settings page from the Site Administration menu. Default Language and Display Language Menu The Default language setting specifies the language that users will see when they first encounter your site. If you also select Display language menu, users can change the language. Selecting this displays a language menu on your Front Page. Languages on Language Menu and Cache Language Menu The setting Languages on language menu enables you to specify the languages that users can pick from the language menu. There are directions for you to enter the 'language codes'. These codes are the names of the directories which hold the Language packs. In the subsection on Language Files on the previous page, you saw that the directory es_utf8 holds the language files for International Spanish. If you wanted to enter that language in the list, it would look like this: Leaving this field blank will enable your students to pick from all available languages. Entering the names of languages in this field limits the list to only those entered. Sitewide Locale Enter a language code into this field, and the system displays dates in the format appropriate to that language. Excel Encoding Most of the reports that Moodle generates can be downloaded as Excel files. User logs and grades are two examples. This setting lets you choose the encoding for those Excel files. Your choices are Unicode and Latin. The default is Unicode, because this character set includes many more characters other than Latin. In many cases, Latin encoding doesn't offer enough characters to completely represent a non-English language. Offering Courses in Multiple Languages The settings on the Language settings page are also applicable for translating the Moodle interface. However, they are not applicable for translating course content. If you want to offer course content in multiple languages, you have several choices. First, you could put all the different languages into each course. That is, each document would appear in a course in several languages. For example, if you offered a botany course in English and Spanish, you might have a document defining the different types of plants in both English and Spanish, side by side in the same course–Types of Plants or Tipos de Plantaras. While taking the course, students would select the documents in their language. Course names would appear in only one language. Second, you could create separate courses for each language, and offer them on the same site. Course names would appear in each language. In this case, students would select the course in English or Spanish– Basic Botany or Botánica Básica. Third, you could create a separate Moodle site for each language, for example, http://moodle.williamrice.com/english and http://moodle.williamrice.com/spanish. At the Home Page of your site, students would select their language and would be directed to the correct Moodle installation. In this case, the entire Moodle site would appear in the students' language: the site name, the menus, the course names, and the course content. These are things you should consider before installing Moodle. Installing Additional Languages To install additional languages, you must be connected to the Internet. Then, from the Site Administration menu, select Language | Language packs. The page displays a list of all available Language packs: This list is taken from Moodle's /install/lang directory. In that directory, you will find a folder for each language pack that can be installed. The folder contains a file called install.php. That file retrieves the most recent version of the language pack from the Web and installs it. This is why Moodle must be connected to the Web to use this feature. If Moodle is not connected, you will need to download the language pack and copy it into the /lang directory yourself. If you don't see the language you want on the list of Available language packs, either it's not available in the official Moodle site, or your list of available languages is out of date. Click to update this list. If the language doesn't appear, it's not available from official sources. Summary In this article, we have seen how Moodle website supports different languages and how to configure these different languages. This feature can be particularly useful while designing courses for students who come from different ethnic backgrounds. Language support can not only make the website more friendlier but also makes it more easy to browse.
Read more
  • 0
  • 0
  • 9098

article-image-linq-objects
Packt
22 Oct 2009
10 min read
Save for later

LINQ to Objects

Packt
22 Oct 2009
10 min read
Without LINQ, we would have to go through the values one-by-one and then find the required details. However, using LINQ we can directly query collections and filter the required values without using any looping. LINQ provides powerful filtering, ordering, and grouping capabilities that requires minimum coding. For example, if we want to find out the types stored in an assembly and then filter the required details, we can use LINQ to query the assembly details using System.Reflection classes. The System.Reflection namespace contains types that retrieve information about assemblies, modules, members, parameters, and other entities as collections are managed code, by examining their metadata. Also, files under a directory are a collection of objects that can be queried using LINQ. We shall see some of the examples for querying some collections. Array of Integers The following example shows an integer array that contains a set of integers. We can apply the LINQ queries on the array to fetch the required values.     int[] integers = { 1, 6, 2, 27, 10, 33, 12, 8, 14, 5 };       IEnumerable<int> twoDigits =       from numbers in integers       where numbers >= 10       select numbers;       Console.WriteLine("Integers > 10:");       foreach (var number in twoDigits)       {          Console.WriteLine(number);       } The integers variable contains an array of integers with different values. The variable twoDigits, which is of type IEnumerable, holds the query. To get the actual result, the query has to be executed. The actual query execution happens when the query variable is iterated through the foreach loop by calling GetEnumerator() to enumerate the result. Any variable of type IEnumerable<T>, can be enumerated using the foreach construct. Types that support IEnumerable<T> or a derived interface such as the generic IQueryable<T>, are called queryable types. All collections such as list, dictionary and other classes are queryable. There are some non-generic IEnumerable collections like ArrayList that can also be queried using LINQ. For that, we have to explicitly declare the type of the range variable to the specific type of the objects in the collection, as it is explained in the examples later in this article. The twoDigits variable will hold the query to fetch the values that are greater than or equal to 10. This is used for fetching the numbers one-by-one from the array. The foreach loop will execute the query and then loop through the values retrieved from the integer array, and write it to the console. This is an easy way of getting the required values from the collection. If we want only the first four values from a collection, we can apply the Take() query operator on the collection object. Following is an example which takes the  first four integers from the collection. The four integers in the resultant collection are displayed using the foreach method.    IEnumerable<int> firstFourNumbers = integers.Take(4);   Console.WriteLine("First 4 numbers:");   foreach (var num in firstFourNumbers)   {      Console.WriteLine(num);   } The opposite of Take() operator is Skip() operator, which is used to skip the number of items in the collection and retrieve the rest. The following example skips the first four items in the list and retrieves the remaining.    IEnumerable<int> skipFirstFourNumbers = integers.Skip(4);   Console.WriteLine("Skip first 4 numbers:");   foreach (var num in skipFirstFourNumbers)   {      Console.WriteLine(num);   } This example shows the way to take or skip the specified number of items from the collection. So what if we want to skip or take the items until we find a match in the list? We have operators to get this. They are TakeWhile() and SkipWhile(). For example, the following code shows how to get the list of numbers from the integers collection until 50 is found. TakeWhile() uses an expression to include the elements in the collection as long as the condition is true and it ignores the other elements in the list. This expression represents the condition to test the elements in the collection for the match.    int[] integers = { 1, 9, 5, 3, 7, 2, 11, 23, 50, 41, 6, 8 };   IEnmerable<int> takeWhileNumber = integers.TakeWhile(num =>      num.CompareTo(50) != 0);   Console.WriteLine("Take while number equals 50");   foreach (int num in takeWhileNumber)      {         Console.WriteLine(num.ToString());      } Similarly, we can skip the items in the collection using SkipWhile(). It uses an expression to bypass the elements in the collection as long as the condition is true. This expression is used to evaluate the condition for each element in the list. The output of the expression is boolean. If the expression returns false, the remaining elements in the collections are returned and the expression will not be executed for the other elements. The first occurrence of the return value as false will stop the expression for the other elements and returns the remaining elements. These operators will provide better results if used against ordered lists as the expression is ignored for the other elements once the first match is found.    IEnumerable<int> skipWhileNumber = integers.SkipWhile(num =>      num.CompareTo(50) != 0);   Console.WriteLine("Skip while number equals 50");   foreach (int num in skipWhileNumber)   {      Console.WriteLine(num.ToString());   } Collection of Objects In this section we will see how we can query a custom built objects collection. Let us take the Icecream object, and build the collection, then we can query the collection. This Icecream class in the following code contains different properties such as Name, Ingredients, TotalFat, and Cholesterol.     public class Icecream    {        public string Name { get; set; }        public string Ingredients { get; set; }        public string TotalFat { get; set; }        public string Cholesterol { get; set; }        public string TotalCarbohydrates { get; set; }        public string Protein { get; set; }        public double Price { get; set; }     } Now build the Icecreams list collection using the class defined perviously.     List<Icecream> icecreamsList = new List<Icecream>        {            new Icecream {Name="Chocolate Fudge Icecream", Ingredients="cream,                milk, mono and diglycerides...", Cholesterol="50mg",                Protein="4g", TotalCarbohydrates="35g", TotalFat="20g",                Price=10.5        },        new Icecream {Name="Vanilla Icecream", Ingredients="vanilla extract,            guar gum, cream...", Cholesterol="65mg", Protein="4g",            TotalCarbohydrates="26g", TotalFat="16g", Price=9.80 },            new Icecream {Name="Banana Split Icecream", Ingredients="Banana, guar            gum, cream...", Cholesterol="58mg", Protein="6g",            TotalCarbohydrates="24g", TotalFat="13g", Price=7.5 }        }; We have icecreamsList collection which contains three objects with values of the Icecream type. Now let us say we have to retrieve all the ice-creams that cost less. We can use a looping method, where we have to look at the price value of each object in the list one-by-one and then retrieve the objects that have less value for the Price property. Using LINQ, we can avoid looping through all the objects and its properties to find the required ones. We can use LINQ queries to find this out easily. Following is a query that fetches the ice-creams with low prices from the collection. The query uses the where condition, to do this. This is similar to relational database queries. The query gets executed when the variable of type IEnumerable is enumerated when referred to in the foreach loop.     List<Icecream> Icecreams = CreateIcecreamsList();    IEnumerable<Icecream> IcecreamsWithLessPrice =    from ice in Icecreams    where ice.Price < 10    select ice;    Console.WriteLine("Ice Creams with price less than 10:");    foreach (Icecream ice in IcecreamsWithLessPrice)    {        Console.WriteLine("{0} is {1}", ice.Name, ice.Price);     } As we used List<Icecream> objects, we can also use ArrayList to hold the objects, and a LINQ query can be used to retrieve the specific objects from the collection according to our need. For example, following is the code to add the same Icecreams objects to the ArrayList, as we did in the previous example.     ArrayList arrListIcecreams = new ArrayList();    arrListIcecreams.Add( new Icecream {Name="Chocolate Fudge Icecream",        Ingredients="cream, milk, mono and diglycerides...",        Cholesterol="50mg", Protein="4g", TotalCarbohydrates="35g",        TotalFat="20g", Price=10.5 });    arrListIcecreams.Add( new Icecream {Name="Vanilla Icecream",        Ingredients="vanilla extract, guar gum, cream...",        Cholesterol="65mg", Protein="4g", TotalCarbohydrates="26g",        TotalFat="16g", Price=9.80 });    arrListIcecreams.Add( new Icecream {Name="Banana Split Icecream",        Ingredients="Banana, guar gum, cream...", Cholesterol="58mg",        Protein="6g", TotalCarbohydrates="24g", TotalFat="13g", Price=7.5    }); Following is the query to fetch low priced ice-creams from the list.     var queryIcecreanList = from Icecream icecream in arrListIcecreams    where icecream.Price < 10    select icecream; Use the foreach loop, shown as follows, to display the price of the objects retrieved using the above query.     foreach (Icecream ice in queryIcecreanList)    Console.WriteLine("Icecream Price : " + ice.Price);
Read more
  • 0
  • 0
  • 2159
Modal Close icon
Modal Close icon