Graph Servlet:用于门户频道的动态图像生成器
作者:Paul Lovvik 和 Beverly Sum
本文档描述了 Graph Servlet 的体系结构,并重点讲述其组件和实现。同时讨论了安装和部署过程、主要实现方面的优缺点以及故障诊断技巧。
目录
- | 体系结构 |
- | 主要组件 |
- | 安装与部署 |
- | 动态图像 |
- | 高速缓存 |
- | 体系结构的优点与缺点 |
- | 故障诊断 |
- | 参考资料 |
- | 关于作者 |
体系结构
该程序包含三个主要组件:
- 驻留在系统类加载器 (
java.awt.ClassLoader
) 中的 Singleton 结构类,它在 Sun ONE Portal Server 和 Graph Servlet 之间共享数据。
- 使用 HTML 和 Java 技术中的 JavaServerPages (JSP) 创建的页面,用以生成频道内容。
- 动态呈现饼形图或条形图的 Java servlet。
图1阐释了体系结构中的请求流。
图1:请求流
图2展示了体系结构的层次。
图2:体系结构
用户与包含控制器的频道通信。视图将动态图像与标准 HTML <img>
标签合并在一起。这个设计围绕以下两个主要难点:
- Sun ONE Portal Server 不能聚合 Java servlet。
- JSP 页面不能生成动态图像,而这些图像正是图形实用程序所必需的。(使用 HTML 是惟一可行的选择) 比如 Time-sheet数据经常地变化并需要不断地升级。
主要组件
本节描述了 Graph Servlet 中的主要组件 —— JSP 页面和 Java 类的组合。
controller.jsp
controller.jsp
是控制器,用于从请求、频道的类 (JSPProvider
) 和用户配置文件 (用于存储任务数据) 中收集信息。收集数据后,controller.jsp
将对这些数据进行处理、排序和调度,以便生成图形。具体来说,controller.jsp
执行以下任务:
- 请求频道名称、将要图形化的活动以及图像的维度。请参见代码示例1-3。
代码示例1:引用 JSPProvider
JSPProvider provider = (JSPProvider)pageContext.getAttribute "JSPProvider"); ProviderContext providerContext = provider.getProviderContext();
代码示例2:从用户配置文件中检索 Collection
属性
newNamesAndTimes = providerContext.getCollectionProperty(channelName, "activities");
代码示例3:从 HttpServletRequest
中检索参数
String activityName = (String)request.getParameter(channelName + "-activity");
注意:Sun ONE Portal Server 6 会将一个频道名称的请求参数传送给当前显示的所有频道。因此,命名时一定要采用 channel_name-parameter_name命名约定,例如,ActivityChannel-activity
,这样便可以将每个请求仅应用于一个频道,而不是多个频道。
- 将活动数据置入
HashMap
以便修改。
- 将数据置入
ActivityElement
数组以进行排序和颜色指定。
- 将数据放入会话和
Singleton
中使之可以存取。
- 适时地添加和删除活动数据。
代码示例 4:将数据置入 HttpSession
session = request.getSession(true); session.putValue("timesheet",elements);
代码示例 5:将数据置入 Singleton
DataFactory.setData(request, elements);
最后,controller.jsp
将按照用户输入确定是显示主视图还是显示图形视图,并将 <img>
标签插入到生成的 HTML 内容中。
main.jsp
main.jsp
显示以下数据,即输出经 controller.jsp
处理和排序后的数据:
- 以表格形式显示活动名称和持续时间。
- 用以选择和删除活动的复选框。
- 用于输入或修改当前活动数据的表单。
- 条形图或饼形图的缩略图;请参见代码示例 6。
代码示例 6:为饼形图添加缩略图
<a href="<dtpc:getDesktopURL/>?<%=channelName%>- view=graph.jsp&<%=channelName%>-style=Pie"><img src="/graph/graphController?width=100&height=100&style=Pie"></a>
- 两个按钮,标签分别为 Add 和 Delete
- 一个 HTML 链接,标签为 Refresh,用于重新载入主视图
graph.jsp
graph.jsp
执行以下任务:
- 根据用户的输入确定是显示条形图还是显示饼形图。
- 为 HTML 表示方法将颜色对象转换为红-绿-蓝 (RGB) 十六进制字符串。
- 显示以下内容:
- 根据用户输入 (在
main.jsp
的两个缩略图中单击任意一个) 显示较大的图形视图。
- 活动的颜色编码表。
- 一个标签为 Back to Main Page 的 HTML 链接。
- 根据用户输入 (在
GraphServlet
GraphServlet
,一种扩展了 HttpServlet
类的 Java servlet,用以执行以下任务:
- 从
controller.jsp
生成的 URL 中获取绘图参数:高度、宽度和样式。
- 为图形创建一个框架。
- 从
DataFactory
获取相关数据(ActivityElement
数组)并将这些数据发送给Pie
或Bar
对象。
- 将图形编码为 GIF 文件。
- 删除
Graphics
和Frame
对象。
代码示例 7:从 HttpServletRequest
收集图形外观数据
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{ ServletOutputStream out = res.getOutputStream(); String width = req.getParameter("width"); String height = req.getParameter("height"); String style = req.getParameter("style"); ..}
注意:在 UNIX 系统中,您可以选择从任何 shell 启动 Web 容器,因此一定要授予用户显示访问权限。请参见 故障诊断。另外,如果运行门户的服务器正在 headless 模式下执行,您也可以使用 Xvfb 服务器软件 启动 Web 容器。
Pie
对象
Pie
对象将信息从 controller.jsp
传递到 DataFactory
,然后再传递到 GraphServlet
,以呈现一个表示活动持续时间的饼形图。Pie
对象执行两个主要任务:
- 计算活动的持续时间。
- 使用浮点转换法和除法使持续时间的总时间缩放为 360 度。具体来说,
Pie
对象执行以下任务:
- 将持续时间转换为整型。
- 如果存在整数圆整错误,使用一种方法对其进行修正。
- 用固定的度数和不同颜色来填充弧形,填充颜色时使用抽象窗口工具套件 (
java.awt.*
) 中的Graphics
方法。
- 缩放饼形图,使之居中。
- 将持续时间转换为整型。
Bar
对象
同样,Bar
对象将信息从 controller.jsp
传递到 DataFactory
,然后再传递到 GraphServlet
,以呈现表示活动持续时间的条形图。它执行三个主要任务:
- 确定最长持续时间的活动。
- 缩放条形图,使其适合图形的高度和宽度范围。
- 使用
java.awt.*
中的Graphics
方法填充矩形,为条形图着色并创建条形图。
DataFactory
对象
DataFactory
对象驻留在系统的类装载器中,用于联系从 Sun ONE Portal Server 传递到 GraphServlet
的数据。在典型的 Singleton
设计中,DataFactory
使用方法 (setData
) 使数据能够存储在 HashMap
中,这样 Sun ONE Identity Server 的 SSOToken
在以后的 getData
方法中便可以引用这些数据。这样,用户便拥有了与其数据相匹配的独占访问权限和惟一的 ID。
要使多条数据与单个用户匹配,可在 DataFactory
中关联保留所有用户数据的容器。
每当 DataFactory
接收到新数据时,它都会检查数据 ID 是否已经存在于映射中,如不存在,则添加一个条目。由于 Sun ONE Identity Server 的每个用户都有一个惟一的 ID,因此用户与其数据之间为独占匹配。
请参见代码示例 8。
代码示例 8:在系统类加载器中设置数据
public static void setData(HttpServletRequest r, Object obj){ String uniqueID = getUniqueID(r); if(h.get(uniqueID) == null){ try{ SSOTokenManager tokenManager = SSOTokenManager.getInstance(); SSOToken s = tokenManager.createSSOToken(r); /* * If the user is logging in for the first time, * DataFactory adds a token listener to watch for session * logouts and timeouts. */ s.addSSOTokenListener(factory); }catch(SSOException e){ d.error("setData method could not get SSOTokenManager", e); } } h.put(uniqueID, obj); }
如果有大量用户同时登入系统,Sun ONE Portal Server 的性能可能会下降。要避免这个问题,只需在 SSOToken
上添加一个事件监听器来监视会话的变化 (用户注销和会话超时),然后从 HashMap
删除关联的数据,从而实现内务处理的清除。请参见代码示例 9。
代码示例 9:从 HashMap
中删除数据以优化性能
public void ssoTokenChanged(SSOTokenEvent evt) { SSOToken token = evt.getToken(); h.remove(token.getTokenID().toString()); }
处理流程如下:
- 从
controller.jsp
返回的内容包含图像标签。
controller.jsp
调用用户配置文件中的数据,并将其发送给DataFactory
对象。
- 浏览器解析标签数据并从
GraphServlet
中请求图像,也就是说,Sun ONE Portal Server 调用controller.jsp
,然后浏览器从GraphServlet
请求图像。
Sorter
对象
Sorter
对象使用 mergesort
方法将对象数组按字母顺序排序。
ActivityElementStringComparator
对象
ActivityElementStringComparator
对象用于比较 ActivityElements
对象数组中的字符串。
NamedColors
对象
NamedColors
对象是从 /usr/openwin/lib/rgb.txt
文件中创建的。NamedColors
按名称存储众多的颜色,以增加图形代码和图形显示的可读性。这些颜色远远超过 java.awt.Color
中的颜色,为图形提供了许多颜色选择。NamedColors
提供了两个方案以获取颜色:静态的 final 类变量和一个静态的 lookup 方法。
ActivityElement
对象
ActivityElement
对象作为数据的存储位置和单个活动的颜色。ActivityElement
的每个实例主要包含 set
和 get
方法。ActivityElement
只执行最低限度的数据处理,这些处理有:
SetDuration
方法接受整型或字符串参数。
controller.jsp
将ActivityElement
实例数组传递到DataFactory
,再传递到GraphServlet
,最后传递到Pie
或Bar
用以图形化和输出。
安装和部署
首先,下载 压缩文档 并将其放到一个临时目录,例如 /tmp
。
安装
安装时请执行以下步骤:
- 解压压缩文档。
- 转至
graphing
目录。
- 键入下面的命令,导入门户档案 (PAR) 文件:
% par import -p
password-r
uid-- TimeTracker.par
dnchannel
在这里:
- password 是登录门户时的口令。
- uid 是系统管理员的标识名称。
- dn 是频道目标的标识名称。
表 1 解释了如何导出 uid 和 dn 的值,并提供了示例。
表 1:标识名称 | ||||||||||||
![]() | ||||||||||||
![]() | ||||||||||||
![]() | ![]() 名称类型 ![]() | ![]() | ![]() 值 ![]() | ![]() | ![]() 示例 ![]() | ![]() | ||||||
![]() | ||||||||||||
![]() | ![]() uid ![]() | ![]() | ![]() install_dir /SUNWam/lib/ AMConfig.properties 文件中的 com.sun.identity.authentication 设置 ![]() | ![]() | ![]() Sun ONE Portal Server 6.0: uid=amadmin,ou=people,o=sun.com,o=isp Sun ONE Portal Server 6.1: uid=amadmin,ou=people,dc=sun,dc=com ![]() | ![]() | ||||||
![]() | ||||||||||||
![]() | ![]() dn ![]() | ![]() | ![]() /SUNWam/lib/ AMConfig.properties 文件中的 com.iplanet.am.defaultOrg 设置 ![]() | ![]() | ![]() Sun ONE Portal Server 6.0: uid=amadmin,ou=people,o=sun.com,o=isp Sun ONE Portal Server 6.1: dc=sun,dc=com ![]() | ![]() | ||||||
![]() |
注意:以下步骤中描述的用户界面适用于 Sun ONE Portal Server 6.0。Sun ONE Portal Server 6.1 和 6.2 中的 UI 稍有不同。
- 执行以下这些步骤,将新的频道添加到门户桌面中:
- 登录到 Administration Console。
- 在左侧面板中选择机构,跟着选择 Show:Services,然后单击桌面左侧 Portal Server Configuration 下面的箭头。
- 在右侧面板的 Display Profile 下单击 Channel and Container Management。
- 在 Container Channels 下的滚动列表中单击要为新频道指定的容器。
要在示例桌面的第一个选项卡中放置新频道,请选择 MyFrontPageTabPanelContainer。
- 在 Existing Channels 的滚动列表中选择 TimeTrackerChannel。
- 在 Available and Visible 滚动列表的左侧单击 Add。
- 单击 Channel Management 下的 Save。
- 退出 Administration Console。
- 登录到 Administration Console。
- 将
DataFactory
类添加到系统类加载器中。请执行以下步骤:
- 为
DataFactory
类创建一个目录:% mkdir /opt/DataFactory
- 将 JAR 文件复制到此目录:
% cp DataFactory.jar /opt/DataFactory
- 将 JAR 文件添加到系统类加载器的
CLASSPATH
属性。
如果门户运行于 Sun ONE Web 服务器,在jvm12.conf
文件中追加jvm.classpath
设置,这个文件位于 install_dir/SUNWam/servers/https-
hostname/config
,加入的字符串是::/opt/DataFactory/DataFactory.jar
- 为
部署
Graph Servlet 驻留在 graph.war
文件中。像部署其他 Web 文档 (WAR) 文件一样部署 Graph Servlet 的 Web 应用。根据不同的 Web 容器,此过程可能会有所不同。如果使用的是 Sun ONE Web 服务器 和 Sun ONE Portal Server 6.0,那么在一行内运行 wdeploy
命令,如下:% wdeploy deploy -u /graph -i instance_name -v virtual_server_name
-d /opt/GraphServlet graph.war
例如:% /opt/SUNWam/servers/bin/https/httpadmin/bin/wdeploy deploy
-u /graph -i gravitywell.sun.com -v https-gravitywell.sun.com
-d /opt/GraphServlet graph.war
最后,重新启动 Sun ONE Portal Server。确保 $DISPLAY
环境设置是正确的,同时在启动门户的 shell 中有正确的访问权限。
动态图像
Graph Servlet 演示了动态图像在 Sun ONE Portal Server 中的应用。Sun ONE Portal Server 一收到用户请求(例如对新图片或者带有修订过数据的请求)就将请求发送到 controller.jsp
。如果请求是改变图形的样式,controller.jsp
将为 main.jsp
和 graph.jsp
在 URL 中创建 style
参数。请参见代码示例 10。
代码示例 10:创建样式参数
<a href="<dtpc:getDesktopURL/>?<%=channelName%>- view=graph.jsp&<%=channelName%>-style=Pie">
随后的过程如下:
main.jsp
和graph.jsp
确定用户请求了哪种图形样式,比如放大或新活动。
main.jsp
和graph.jsp
调用DataFactory
中的setData
方法,并派送请求和数据到系统类加载器,供以后的DataFactory
访问。
DataFactory
将请求的SSOToken
ID 和数据进行匹配,并将数据作为易于理解的对象进行处理。
GraphServlet
调用Pie
或Bar
来呈现图形。
传递给 Graph Servlet 的数据在 URL 中是可视的,并包含图形的重要参数,如宽度、高度以及样式。
注意:null 值参数将导致错误。请确保为参数设置了默认值。
高速缓存
作为改善性能的方案,高速缓存存储最近生成的数据并用于后续的请求。
Graph Servlet 支持高速缓存,这样可确保频道的视图能保持连续,甚至在刷新之后或用户从浏览其他内容返回之后也是如此。
体系结构的优点与缺点
软件解决方案中包含多种任务。具体采用哪种解决方案,主要取决于代码的“简洁度” —— 程序越简洁明了,解决方案就越健壮。例如,Graph Servlet 只使用一个 servlet 来生成饼形图和条形图。如果使用两个 servlet 将使部署过程复杂化并增加实现的费用。
下面是对 Graph Servlet 设计方面的优缺点分析:
JSPProvider
与其他内容提供者JSPProvider
使用 JSP 页面创建桌面频道内容。由于以下这两个主要优势,JSPProvider
相对其他内容提供者(例如ProfileProviderAdapter
)来说,提供了更有效的开发周期:
JSPProvider
提供了从表示层分离逻辑层的标准方案:JSP 页面文件包含表示层;大多数逻辑层驻留在分离类的 Java 代码中。
JSPProvider
可以在不必重新启动 Web 服务器的情况下更新 JSP 页面。
- 系统类加载器中的数据与会话数据
您不能访问门户的session
对象,且分离的 Web 应用不能共享同一会话。重新调用会话以在不同 Web 应用间共享数据,您可以将这些数据存储在从系统类加载器载入的Singleton
类中。
- 深度集成与浅层集成
在采用浅层集成的体系结构中单击频道内的链接将为目标位置打开一个新浏览器窗口。
Graph Servlet 采用深度集成,即剩余程序在其自身频道内。因此,当您单击 Graph Servlet 频道内的链接时,该频道内的视图就会变化,导致对屏幕内容的保存。
深度集成需要更复杂的实现。然而,它的许多优点都可在同一桌面上访问到,而不需要付出额外的努力。这些优点包括,减少了弹出窗口的数量,并且对 安全远程访问附加产品 的集成更稳定。对于大多数的 Sun ONE Portal Server 频道,深度集成提供了更健壮的用户界面。
- 通过 URL 的共享数据与其他方案
因为不能访问会话数据,所以GraphServlet
使用HttpServletRequest
对象中的参数来接收信息。此方案不仅是一个简单的共享数据解决方案,还能揭示数据是否从一个组件正确地传递到了另一个组件 —— 这是调试时最有用的线索。
使用此方案的优点在于用户可以修改 URL 中的参数,在浏览器中可以清楚地看到 URL。
故障诊断
您可以在系统控制台或 Web 服务器日志中查找解决问题的线索。还可以启动调试进程解决问题,方法如下:
- 以 root 身份登录,修改
/opt/SUNWam/lib/AMConfig.properties
文件。
- 将其设置为您需要的级别以激活调试:
error
、warning
、message
或all
。
- 插入
com.iplanet.am.util.*
包的Debug
类中的调试语句。保存更改。
表 2 描述了公共错误条件及解决问题的建议。
表 2:错误条件和故障诊断技巧 | ||||||||||||||
![]() | ||||||||||||||
![]() | ||||||||||||||
![]() | ![]() 错误 ![]() | ![]() | ![]() 故障诊断技巧 ![]() | ![]() | ||||||||||
![]() | ||||||||||||||
![]() | ![]() 图像不能显示 ![]() | ![]() | ![]()
![]() | ![]() | ||||||||||
![]() | ||||||||||||||
![]() | ![]() 图形视图破坏了其他门户频道 ![]() | ![]() | ![]() 可能未在 URL 中指明频道名称,这将导致 Sun ONE Portal Server 6 将请求发送到所有频道。当定义 URL (例如,您选择的视图) 变量时,请确保频道名称完全正确。下面是一个正确的 URL 示例: <a href="<dtpc:getDesktopURL/>?<%= channelName%>- ![]() | ![]() | ||||||||||
![]() | ||||||||||||||
![]() | ![]() 不显示数据 ![]() | ![]() | ![]() 验证 JSP 页面中的代码是否已将数据置于 DataFactory 对象中![]() | ![]() | ||||||||||
![]() | ||||||||||||||
![]() | ![]() graph.jsp 不能访问所需数据![]() | ![]() | ![]() 确保已将类文件部署到正确位置,且 Web 应用指向正确的目标 ![]() | ![]() | ||||||||||
![]() |
参考资料
关于作者:
Paul Lovvik 有六年的 Sun 工作经历,他是 Sun ONE Portal Server ISV 组在市场拓展中的首席工程师。在过去的两年中,Paul 和他的团队为 Sun ONE Portal Server 的 ISV 解决方案设计了接近 40 个集成环境。
Beverly Sum 是一个对编程有强烈兴趣的中学生,2003 年夏天与 Sun 签约。她在 Paul 领导的团队中开发 Graph Servlet。
Marina Sum 是 Sun Developer Network 的专栏作家。14 年来,她一直为 Sun 从事写作工作,写作内容大多涉及技术领域。