ContextInternals.getApplicationContext(requestContext);
// If the accept headers indicate that WMLC is supported, create a
// WBXML producer. If not, default to WMLProducer.
WBSAXContentHandler handler = null;
WBSAXDocumentOutputter wbsaxOutputter;
WBSAXContentHandler producer;
// If the user has not asked to know the output style of this protocol,
// then we will not have calculated whether we will be generating WMLC.
// In this case we better generate it now as we are about to need it.
if (generateWMLC == null) {
calculateGenerateWMLC();
}
// Check that the outputs of calculateGenerateWMLC are available.
if (charsetCode == null || generateWMLC == null) {
throw new IllegalStateException(
"charsetCode and generateWMLC must be available");
}
EnvironmentContext envContext = context.getEnvironmentContext();
if (Boolean.TRUE.equals(generateWMLC)) {
// Generate binary WMLC.
envContext.setContentType("application/vnd.wap.wmlc");
producer = new WBXMLProducer(output.getOutputStream());
} else {
// For WML, the entity encoding is done now. The encoding writer
// is passed to the producer to do the encoding.
envContext.setContentType("text/vnd.wap.wml");
Writer out = output.getWriter();
Writer enc = new EncodingWriter(out, getCharacterEncoder());
producer = new WMLProducer(out, enc);
}
SerialisationURLListener urlListener = null;
final PackageResources pr = appContext.getPackageResources();
if (pr != null) {
// Force the packager to understand that only a subset of
// assets are likely to be included in the response
pr.initializeEncodedURLs();
urlListener = new SerialisationURLListener() {
public void foundURL(String url) {
pr.addEncodedURLCandidate(url);
}
};
}
WMLRootConfiguration wmlConfiguration = (WMLRootConfiguration)
protocolConfiguration;
Encoding charsetEncoding = context.getCharsetEncoding();
if (charsetEncoding == null) {
throw new RuntimeException(
exceptionLocalizer.format("charset-not-found"));
}
// Create the shared context that all the objects which participate
// in serialising the MCSDOM use.
Codec codec = new Codec(charsetCode);
StringTable stringTable = new StringTable();
StringFactory strings = new StringFactory(codec);
StringReferenceFactory references =
new StringReferenceFactory(stringTable, strings);
WBSAXProcessorContext processorContext =
new WBSAXProcessorContext(
wmlConfiguration.getElementNameFactory(),
wmlConfiguration.getAttributeStartFactory(), strings,
references, charsetEncoding, stringTable,
wmlConfiguration);
// Create the WBSAXDocumentOutputter - this serialises the MCSDOM into
// WBSAX events. This will then be configured for any special
// processing that it needs to do.
wbsaxOutputter = new WBSAXDocumentOutputter(processorContext);
// Set up the null name element processor.
// This will ignore any null name elements introduced into the MCSDOM
// during the DOM optimisation process.
wbsaxOutputter.addSpecialElementProcessor(null,
new WBSAXIgnoreElementProcessor(
processorContext));
// todo: move "final" disassembler here to show accesskeys
// Otherwise it is too late to capture accesskey output properly and
// you will see null data in AccesskeyOpaqueValues rather than the
// appropriate accesskey values which appear in the output (hopefully).
// This will require refactoring since the "final" disassember is
// currently cut and pasted below twice (dissection/none).
// It might be a good idea to add a description to the disassember
// constructor as well since dissection uses multiple disassemblers in
// one pipeline.
// If this protocol supports access key attributes...
if (supportsAccessKeyAttribute) {
// ... then set up the special processing for access keys.
// This is required to calculate access key values when we are
// using numeric shortcut style menus against WML which, unlike
// Openwave, does not support this automagically.
// NOTE: we could slightly improve performance by only doing this
// when actually required, but whether it is worth calculating this
// is not clear at this stage.
//
// This consists of two parts as outlined below.
// First, we add a special element processor to the outputter which
// picks up any special ACCESSKEY-ANNOTATION elements that have
// been inserted into the MCSDOM by the protocol for each element
// which uses an accesskey which requires a calculated value and
// translates them into special opaque WBSAX events during the
// MCSDOM output phase.
boolean doesDeviceDisplayAccesskeyNums =
context.getDevice().getBooleanPolicyValue(DevicePolicyConstants.
SUPPORTS_WML_ACCESSKEY_AUTOMAGIC_NUMBER_DISPLAY);
wbsaxOutputter.addSpecialElementProcessor(
AccesskeyConstants.ACCESSKEY_ANNOTATION_ELEMENT,
new WBSAXAccesskeyAnnotationElementProcessor(processorContext,
!doesDeviceDisplayAccesskeyNums));
// Second, we add a special filter to the producer which picks up
// the special opaque WBSAX events created by the element processor
// above and calculates the appropriate accesskey value as required
// during the WBDOM output phase. This needs to be done here so
// that dissection doesn't end up throwing accesskey values away.
producer = new AccesskeyWBSAXFilter(codec, producer,
wmlConfiguration.getAttributeStartFactory());
}
if (isDissectionNeeded()) {
prepareAndWriteViaDissection(wbsaxOutputter,
producer,
urlListener,
wmlConfiguration,
processorContext,
handler);
}
else {
// We are writing out directly rather than via WBDOM and
// dissection.
StringWriter out = null;
try {
if (logger.isDebugEnabled()) {
out = new StringWriter();
handler = new WBSAXDisassembler(producer, out);
} else {
handler = producer;
}
processorContext.setContentHandler(handler);
// Since we are writing out directly, we must configure the
// WBSAX Outputter to do the things that the dissector would
// normally do.
processorContext.setFinalOutput(true);
processorContext.setUrlListener(urlListener);
wbsaxOutputter.output(document);
} finally {
if (logger.isDebugEnabled()) {
out.flush();
logger.debug(out);
}