27 December 2015
21 November 2015
26 October 2015
05 October 2015
For example, a network socket class implemented by Bob Eins—because
socket.hwas Not Invented Here, and thus not good enough—was namespaced as
base::universe::posix::network::socket::Constants::IPV4. It was unclear what existed outside of the
24 September 2015
19 September 2015
16 August 2015
01 August 2015
18 July 2015
01 July 2015
We have standard logic that we want to execute for the invocation of any action (authentication, logging, timing, etc.), so I've recoded our Struts 1 filters as interceptors.
Then there is exception handling. It took me several readings of the documentation and various forum postings and some trial and error to get this working the way we need it, including being able to catch exceptions thrown by interceptors. I ended up deciding to pass the exception info directly to a view JSP, rather than an action class, but we might revisit that decision and do some refactoring.
The docs explain how to configure a handler to be applied globally to the entire application, and how to configure an action-specific handler. But in our case, we have one module that consists of actions that respond to Ajax requests, and hence render JSON, while the other modules render complete web pages with JSPs. The problem statement: how can you configure a Struts 2 global exception handler with the <global-exception-mapping> tag that will apply to a specific package, but will share the same interceptor stack with the rest of the application? For actions in our JSON module, we want error info returned as JSON payload, not HTML.
Well, it turns out that you can do it, but you have to be a little creative with the package inheritance hierarchy. What follows is a simplified (and slightly redacted) version of our actual application, so I can't vouch that this code is complete and accurate, but it should give you the general idea.
The key is to make a package just for the interceptors. Then every other package extends that package. The
corepackage defines exception handlers and global results that all packages use, except the
jsonpackage, which defines its own.
Here's the struts.xml (again, in our production solution, every package is defined in a separate file that is brought in with <include>, but it's easier to see what's going on with everything in one place):
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <constant name="struts.convention.default.parent.package" value="interceptors"/> <package name="interceptors" namespace="/" extends="struts-default"> <interceptors> <interceptor name="appTracer" class="org.CLIENT.cmsui.interceptor.TracerInterceptor" /> <interceptor name="appAuthentication" class="org.CLIENT.cmsui.interceptor.AuthenticationInterceptor" /> <interceptor-stack name="appStack"> <interceptor-ref name="exception"> <param name="logEnabled">true</param> <param name="logLevel">ERROR</param> </interceptor-ref> <interceptor-ref name="appTracer"> <param name="message">===begin interceptor stack===</param> </interceptor-ref> <interceptor-ref name="appAuthentication" /> <interceptor-ref name="defaultStack" > <param name="exception.logEnabled">true</param> <param name="exception.logLevel">ERROR</param> </interceptor-ref> </interceptor-stack> </interceptors> <default-interceptor-ref name="appStack" /> </package> <package name="core" namespace="/" extends="interceptors"> <global-results> <result name="generalExceptionResult">/jsp/GeneralException.jsp</result> <!-- results returned by authentication interceptor --> <result name="passwordWrongResult">/jsp/user/UserLogin.jsp?passwordWrong=true</result> </global-results> <global-exception-mappings> <exception-mapping exception="java.lang.Exception" result="generalExceptionResult"/> </global-exception-mappings> </package> <package name="alpha" namespace="/alpha" extends="core" > <action name="EditAlpha" class="org.CLIENT.cmsui.alpha.action.EditAlphaAction" > <result name="Success">/jsp/alpha/EditAlpha.jsp</result> </action> </package> <!-- and similarly for packages bravo, charlie --> <package name="json" namespace="/json" extends="interceptors" > <global-results> <result name="generalExceptionResult">/jsp/GeneralException.jsp</result> <result name="jsonExceptionResult">/jsp/JsonException.jsp</result> <!-- results returned by authentication interceptor --> <result name="passwordWrongResult">/jsp/user/UserLogin.jsp?passwordWrong=true</result> </global-results> <global-exception-mappings> <exception-mapping exception="java.lang.Exception" result="jsonExceptionResult"/> </global-exception-mappings> <action name="GetLookupInfo" class="org.CLIENT.cmsui.json.action.GetLookupInfoAction" > <result name="Success">/jsp/json/GetLookupInfo.jsp</result> </action> </struts>
A couple of things to point out:
- Notice that we use <global-results> to account for results returned by interceptors, as well as the exception handling mechanism.
- I consider it a blot that you have to define <global-results> in two places, in both the
jsonpackages, but that's apparently what you have to do.
- I recommend creating a tracer interceptor as part of your tool kit. All that it does log a message (here, set as a configurable parameter). Writing the code is a good tutorial for creating your first interceptor from scratch, and once you've got it, you can use it to debug your interceptor stacks. I've only shown one stack in this example, but when your requirements call for alternative stacks, it's good to know that you're executing the one you want.
09 May 2015
22 April 2015
21 April 2015
- Brian Hayes works through Fawn Nguyen's multiplication problem for her sixth graders, and uses shoe-lacing diagrams to analyze the solution.
- Guy Fedorkow gives a virtual tour of the Computer History Museum's IBM 1401 mainframe, and delves into the intricacies of data processing with master and detail card decks.
- Congratulations to the inaugural winners of the Powerful Women Programmers award, 30 talented women from the D.C. area (including three of my past and present colleagues!) recognized by DCFemTech.
- Colleague Davar Ardalan gives her take on digital storytelling.
23 March 2015
15 March 2015
11 March 2015
Today was a 60/40 day. Except that, instead of the room's kickball, it was 83K rows from a key table in the central CMS database. A backup copy of the database, a magic Perl script, and the help of Jason, Stephen, Justin, Paul, and Jared, and the rows have been retrieved from the woods.
09 March 2015
This project has also given us the chance to really think about our products in general, and not just thinking about the website, or the mobile site, but also thinking about our overall digital products. The product is companionship. How do we become a better companion to people?ᔥ Greetings from Evanston, Ill.
03 March 2015
15 February 2015
03 February 2015
When Antenna Design came in, commuters were having a hard time adjusting to a pay-first interface, a system much like BART’s current ticket machines. “I saw immediately that wasn’t going to work,” said [Masamichi] Udagawa, “the interface was a big problem.”
New Yorkers simply didn’t trust the machines.
26 January 2015
On the server side, we re-integrated podcast channels and episodes into the overall data model. Now, podcasts are first-class objects in the CMS, peers of blog posts, news stories, topic landing pages, bios, and other kinds of content. Podcasts now can be associated with multimedia assets like video—oh, and audio—just like everything else in our digital universe.
20 January 2015
"Everybody who ages is going to be their own problem-solver," she says.