Implementation Notes

To minimize the impact on the existing file structure, the application will be implemented as a set of ASP pages that will be interspersed with the existing project directories and files. The root directory will be shared as an IIS virtual directory, and home pages within the root, client, and project subdirectories will provide navigation links to the workflow system users.

Combining Online and Offline Users

By mixing a Web application with data from a regular file share, we expose ourselves to various problems. To users of the file share, the client and project directories look like a normal hard drive. The IIS Web server, on the other hand, will interpret some types of files (such as ASP scripts) differently. In particular, we have these concerns:

  • File-share users accidentally damage the Web application.

  • Data files being inadvertently executed by the Web server.

  • Web application files being mistaken for data files by file-share users.

To prevent the file-share users from inadvertently damaging the workflow application, Windows NT (or 2000) file access permissions should be used. This will prevent local users from accidentally overwriting Web application files with other files with the same name. Application development users should be added to a single group, and only that group should be given write access to application source files. Another simple step that can be taken to prevent name collisions is to prepend an underscore (_) character to all of our application's filenames (for example, utilities.inc becomes _utilities.inc).

The second problem is a bit more difficult. By default, various file extensions are associated with Microsoft IIS script processing DLLs. This means that if a file-share user should happen to create a project file with a recognized extension (such as .ida, .shtml, or .asp), IIS would attempt to execute it rather than deliver it to the Web-site user.

One solution to this problem is to remove these file-extension associations from the workflow application virtual directory. This can be done using the Internet Services Manager. The installation instructions, which can be found on this book's Web site, show how the Internet Services Manager can be used to modify the default file-extension associations to minimize the chance that unintended code will be executed. For this application, all ASP pages will have the extension .aspx.

The simplest answer to the last issue (application files being mistaken for data) is to mark all the Web application files as hidden. They will still be interpreted properly by IIS, and most file-share users will not see them. Only advanced users (who enable viewing hidden files) will see them.

Security Considerations

On the Internet, security is always a primary concern. For this application, it is important to ensure that only authorized users can view the project contents over the Web. Also, user security is required so that the current owner of the project can be identified.

Combining NTFS file access control lists with the various directory security options available through IIS, the workflow application can force Internet users to log in using either Basic Authentication (supported by most Web browsers, but not very secure) or Windows NT Authentication (which is supported only by Microsoft Internet Explorer 5.0 and above). The workflow application can then use the contents of the Request.ServerVariables("AUTH_USER") variable as a trusted user ID within the application. This will be the same as the NT logon name (either user or domain user). Later, when we dissect the _project.xml file, we will see how this name is used to control application flow.

Application Structure

Basically three types of users must be accommodated by the system: agency employees, clients, and third-party vendors. Although it is beyond the scope of this application, the NT file permissions would be configured to allow these different types of users different levels of access to the directory tree. Agency employees would be given full access to all clients and files, whereas clients would be able only to view the contents of their own client folder. And third-party vendors (such as printers or publishers) would be limited to viewing only those projects and files that were necessary to do their job.

Based on these user types, Figure 13.3 shows the site navigation map for the application. See page 137 for an example of online workflow application Web-site navigation.

Figure 13.3. Online workflow application Web-site navigation.


Root Directory and Client Home Pages

The physical directory structure of the application actually mirrors the logical organization of the Web site, so the obvious solution is to create a home page for the root directory and each client directory that displays a list of its subdirectories as hyperlinks. Then, as client and project directories are added and removed, the Web site will automatically reflect the changes. Listing 13.1 shows the VBScript code for the ShowDirMenu() subroutine. This subroutine is used by the client and project home pages to display a list of hyperlinks to their child directories.

Listing 13.1. The ShowDirMenu Subroutine
<OBJECT RUNAT="Server" SCOPE="Page" ID=fso PROGID="Scripting.FileSystemObject">
</OBJECT>
<OBJECT RUNAT="Server" SCOPE="Page" ID=pc PROGID="MSWC.PermissionChecker">
</OBJECT>

<%
  Sub ShowDirMenu(strParentDir)
%>
  <ul>
<%
  Dim dir
  Set dir = fso.GetFolder(Server.MapPath(strParentDir))

  Dim fld

  For Each fld In dir.SubFolders
    If (fld.Attributes And 2) = 0 And pc.HasAccess(fld.Path + " _default.aspx") Then
%>
  <li><a href="<%=strParentDir & "/" & fld.Name%>"><%=fld.Name%> </a></li>
<%
    End If
  Next
%>
  </ul>
<%
  End Sub
%>
						

This code uses the ASP Scripting.FileSystemObject object to enumerate the physical subdirectories of the directory given (which may be “.” for the current directory). The single If statement performs a test to see whether the directory is hidden (the 2-bit is set) and whether the current user is permitted to see it. To perform the access check, it uses the MSWC.PermissionChecker object that ships with IIS.

Note

For some reason, the HasAccess() method of the PermissionChecker object does not work correctly when given a directory path. The code therefore has to check for a file that is known to exist (_default.aspx) in the target directory.


The ASP code for each client home page is identical. Rather than copying the code for the entire page to each client directory, a simple stub file that uses the #include ASP directive to include the actual page is used. Then any changes that are made to the master document (_clienthome.aspx) will be automatically propagated to all the client directories.

Project Document DTD

The details about the project (list of participating users, which type of workflow is being used, current workflow state, user role assignments, and project history) are stored in a file called _project.xml. Each project has its own distinct XML document so that different workflows and groups of users can be easily supported. Before you examine a specific document instance, it is useful to look at the project document type definition. The complete DTD can be found in the _workflowproject.dtd file.

The document element type for a project document is <project>, which is declared like this:

<!ELEMENT project (name, current_state, workflow, users, roles, history)>

The first two element types (<name> and <current_state>) are leaf nodes that contain global information about the project. The name is a simple string. The text of the <current_state> element is actually a reference to one of the <state> elements of the document's workflow.

Note

If you're familiar with XML, you might wonder why this application doesn't use the ID and IDREF attribute type mechanism to create the link between the <current_state> and <state> elements. The major limitation of the ID/IDREf framework is that the values used must match the XML Name production. In this application, the state name also doubles as a descriptive label for UI purposes. XML names must begin with a letter, cannot have spaces, and allow only limited punctuation (_ or :).


The <workflow> element type provides the capability to fully describe a complex workflow, such as the one shown in Figure 13.2. The XML declaration of a workflow is a collection of <state> and <action> elements, declared like so:

<!ELEMENT workflow (state+)>
<!ATTLIST workflow
  start_state CDATA #REQUIRED
>

<!ELEMENT state (action*)>
<!ATTLIST state
  name CDATA #REQUIRED
  owner CDATA #IMPLIED
>

<!ELEMENT action EMPTY>
<!ATTLIST action
  target CDATA #REQUIRED
  desc CDATA #IMPLIED
>

What this means is that a workflow is composed of one or more states, and a state has zero or more actions. A state must have a name and an owner attribute. To allow workflows to be easily reused, the owner attribute is an abstract role name that points to a <role> element within the document. Later, we'll see how this extra level of abstraction allows new projects to be quickly defined.

A <workflow> element must have a start_state attribute that is used as the starting point for a new workflow. The application uses this attribute when a project document has an empty <current_state> element (such as when it is first created).

The collection of <action> elements for a particular state defines how the project can advance from one state to another. Within the application, the current project owner is shown these options as part of the project home page. When the project owner selects a particular action, the application updates the <current_state> element of the document.

The <users> element contains a directory of all the actual system users that will fill roles in the workflow. It is a simple list of <user> elements, declared as shown here:

<!ELEMENT users (user*)>

Each <user> element represents a system user ID (which the ASP application gets from the Request.ServerVariables("AUTH_USER") value). By mapping system user IDs to <user> elements, the ASP application can access additional user information (such as the user's real name and email address). The following XML declarations define the contents of the <user> element:

<!ELEMENT user (name, title, company, email)>
<!ATTLIST user
  userid ID #REQUIRED
>

<!ELEMENT title (#PCDATA)>

<!ELEMENT company (#PCDATA)>

<!ELEMENT email (#PCDATA)>

<!ELEMENT name (#PCDATA)>
						

The <roles> element serves as a map between system users and workflow role names. Each <state> element within a <workflow> has an owner attribute, which is a role name. The ASP application uses the list of roles to map this owner role name to an actual system user ID. The contents of the <roles> element is declared to be

<!ELEMENT roles (role+)>

<!ELEMENT role EMPTY>
<!ATTLIST role
  name CDATA #REQUIRED
  userid CDATA #REQUIRED
>

This two-step lookup process allows the same workflow to be used in multiple projects. If user IDs were hard-coded into the workflow specification, the workflow itself would need to be copied and modified for each project. In the next section, the operational aspects of XML content reuse are addressed in more detail.

The final top-level element in a <project> document is the <history> element. Whenever the current project owner advances the project to a new workflow state, the ASP application inserts a new <state-change> element into the history. This state-change record includes information about the old project owner, the previous workflow state, the new state, the date and time the change occurred, and a user comment. This history is later displayed to all project users on the project home page. These are the declarations for the <history> element:

<!ELEMENT history (state-change*)>

<!ELEMENT state-change (owner, old-state, new-state, timestamp, comment)>

<!ELEMENT owner (#PCDATA)>
<!ATTLIST owner
  role CDATA #REQUIRED
  userid CDATA #REQUIRED
>

<!ELEMENT old-state (#PCDATA)>
<!ELEMENT new-state (#PCDATA)>
<!ELEMENT timestamp (#PCDATA)>
<!ELEMENT comment (#PCDATA)>
						

Implementing a _project.xml Document

To gain access to information about a project, the ASP application simply causes MSXML to parse the appropriate _project.xml document file on the server. This is a normal XML document, and it is subject to the normal rules of well-formedness and validity of any XML 1.0 document. How a project document is created is beyond the scope of this project, but for the ASP application to interpret it properly, it must conform to the document type definition in _workflowproject.dtd.

Although all the content for the project document could be contained in a single file, XML provides support for including external content through the external parsed entity facility. Listing 13.2 shows a sample project document that uses external entities to include document content.

Listing 13.2. A Sample Project Document
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE project SYSTEM "../../_workflowproject.dtd" [

<!--
  This entity reads a list of current system users from
  the database in XML format.
-->
<!ENTITY system_users SYSTEM
    "http://www.strategicxml.com/examples/workflow/demo/_system-users.xml">
<!--
  The next entity links to the workflow that will be used for this project.
-->
<!ENTITY new-magazine-ad-workflow SYSTEM
    "../../_workflows/_new-magazine-ad.ent">
]>
<project>
  <name>Widget World Magazine Ad.</name>
  <current_state>copy proofing</current_state>
  &new-magazine-ad-workflow;
  <users>
    &system_users;
  </users>
  <roles>
    <role name="copywriter" userid="aalpha"/>
    <role name="proofreader" userid="bbravo"/>
    <role name="graphic_designer" userid="ccharlie"/>
    <role name="lawyer" userid="ddelta"/>
    <role name="account_exec" userid="eecho"/>
    <role name="client_rep" userid="ffoxtrot"/>
    <role name="ad_sales_rep" userid="ggolf"/>
  </roles>
  <history>
    <state-change>
      <owner role="copywriter" userid="aalpha">Alex Alpha</owner>
      <old-state>copy development</old-state>
      <new-state>copy proofing</new-state>
      <timestamp>5/19/2001 11:26:42 PM</timestamp>
      <comment>Ready for artwork.</comment>
    </state-change>
  </history>
</project>
						

Two external entities are declared in this document: system_users and new-magazine-ad-workflow. The first one is used to include a list of <user> elements that will participate in the workflow. The second entity includes a predefined magazine ad–creation workflow from the _new-magazine-ad.ent file. There are important differences between how the files containing the two entities are referenced and how the actual file contents are generated.

The SYSTEM keyword in each entity declaration indicates that the entity should be loaded using the URL given. In this case, the URL for the system_users entity is a fully qualified HTTP URL that points to an entity on this book's Web site (www.strategicxml.com). No matter where this project document is located, the user list will always be loaded using that particular URL.

The new-magazine-ad-workflow entity, however, is a relative URL that points to a subdirectory somewhere above the directory where the document is located. Notice that there is no protocol (for example, :) given in the URL itself. This indicates to the XML parser that it should use the same protocol as was used to load the original XML document. For example, if the _project.xml file were loaded using a URL, such as

http://localhost/workflow/Acme%20Widgets/Widget%20World%20Project/_project.xml

the XML parser would attempt to load the new-magazine-ad-workflow entity using the following URL:

http://localhost/workflow/_workflows/_new-magazine-ad.ent

But if the XML parser loaded the project document using a file path, such as

file://c:/workflow/Acme%20Widgets/Widget%20World%20Project/_project.xml

then the parser would use a file URL to find the entity:

file://c:/workflow/_workflows/_new-magazine-ad.ent

The choice between absolute and relative URLs should be made on a case-by-case basis, depending on the requirements of the document. For instance, encoding a fully qualified URL to a Web server is convenient if the document will be parsed only on Internet-connected computers. Relative URLs enable documents to be freely relocated, as long as their surrounding directory structure is intact.

Another convenient feature of loading portions of the document via external entities is that the source of the external content can vary. In this case, the content for the system_users entity is loaded from a URL on the Strategic XML Web site. The XML parser doesn't need to be aware of how the content is generated by the Web server, any more than a user's Web browser needs to be concerned about how a Web page is written.

In this case, the information about the system users is stored in an Access database that is updated by the agency personnel. This database has a table named Users that contains a row for every NT user that will use the workflow system. The strUserName column gives the login name that needs to be used in the userid attribute of each <user> element. There are several options for generating the requisite <user> elements from the data in the database:

  • Have a user manually generate the external entity file from the data in the database, and host the document on the Web site.

  • Write a batch program to generate the entity file on demand, and store the generated file on the Web server.

  • Generate the entity file dynamically, using server-side scripting.

Although the first two options might be acceptable (depending on the frequency and scope of the changes made to the database), the last option is remarkably simple to implement using the power of IIS's ASP scripting engine. Although by default only files ending in .asp are interpreted by the ASP scripting engine, modifying the file-extension associations through the Internet Services Manager can cause any text file (such as an XML document) to be interpreted as an ASP script.

Although there will be some performance consequences for documents of the same type that are completely static, creating this association is a low-impact operation. Unless the <%%> ASP delimiters appear in a document, the ASP processor will simply echo the entire document to the HTTP client verbatim. Figure 13.4 shows the Application Configuration dialog after the .xml extension has been associated with the ASP script processor.

Figure 13.4. Enabling dynamic XML scripting on IIS.


For the most part, generating an XML document for use by an XML parser is not much different from generating an HTML document for use by a Web browser. Listing 13.3 shows the source code for the _system-users.xml script that generates a list of <user> elements using the FirstVirtualAgency.mdb sample database.

Listing 13.3. _system-users.xml Source Code
<%@ language="vbscript" %>
<% Option Explicit %>
<!--#include file="_utilities.inc"-->
<%
  Response.ContentType = "text/xml"
  Dim cn
  Set cn = Server.CreateObject("ADODB.Connection")
  cn.Open "SXML-FVADemo"

  Dim rs
  Set rs = Server.CreateObject("ADODB.Recordset")

  rs.Open "select * from UserCompanyView", cn

  If Not rs.BOF Then
    While Not rs.EOF
%>
    <user userid="<%=XMLEscape(rs("strUserName"))%>">
      <name><%=XMLEscape(rs("strName"))%></name>
      <title><%=XMLEscape(rs("strTitle"))%></title>
      <company><%=XMLEscape(rs("strCompanyName"))%></company>
      <email><%=XMLEscape(rs("strEmailAddr"))%></email>
    </user>
<%
      rs.MoveNext
    Wend
  End If
%>
						

The basic code flow should be very familiar to any ASP programmer who has worked with databases using ActiveX Database Objects (ADO). First an ADO Connection is opened to the database, and then a Recordset is created and opened. The SQL statement used to open the recordset returns all the rows from an Access view called UserCompanyView. Then the script loops through each row, emitting a single <user> element for each.

Each of the values to be included in the XML documents is passed through the XMLEscape() function. This function is located in the _utilities.inc ASP include file. Because certain characters cannot appear within parsed character data (most importantly <, >, and &), this function escapes them using the predefined &gt;, &lt;, and &amp; entities.

The only line of code that might be somewhat unfamiliar to an ASP programmer is this:

Response.ContentType = "text/xml"

This is not absolutely necessary for our application, but it is a good idea. By explicitly setting the content type, a Web browser will be able to properly format and display the content of the page if it is requested directly. Unlike Windows, in most cases the Web browser will ignore the extension of the file and honor the MIME type sent through this mechanism. In this case, the stream will be read directly by an XML parser, and the MIME type will not be significant.

Note

Although this feature allows browsers to display XML documents, in this particular case the _system-users.xml page is not a well-formed XML document. Well-formed documents have only one top-level element, and this script generates a list of <user> elements without an enclosing document element. This is not a problem when it is included as an entity, but it cannot be parsed by itself.


The other entity (new-magazine-ad-workflow) simply links to a static file that contains the new magazine ad workflow. Storing these workflows separately enables them to be reused for different projects.

The Project Home Page

Although some users might actually prefer to read the raw XML source for a project, most would prefer a more user-friendly HTML version. Also, the application logic for moving from one workflow state to another must be implemented somewhere. Each project directory has a home page that performs the following functions:

  • Displays global project information.

  • Shows a list of hyperlinks to the project data files.

  • Gives the current workflow status and owner of the project. Provides options for moving to another workflow state to the owner of the project.

  • Lists the complete project history, including user comments, status changes, and timestamps.

All of this information resides in the _project.xml document that is in each project directory. The project home page parses this document, then constructs the appropriate HTML view of the data for the current user. The HTML is generated using a combination of ASP and XSLT techniques. Figure 13.5 shows an example of the project home page as it might appear to the current project owner.

Figure 13.5. The project home page for the current project owner example.


The ASP code for displaying this page is located in _projecthome.inc and _utilities.inc. See the source-file comments for more detailed information about how the page is generated. There are a few peculiarities about server-side XML parsing using MSXML that need to be addressed both within the application source code and on the Web server itself. See the the installation notes for more information about server-side XML parsing.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.35.255