On May 4, 2006, at 12:52 PM, Apache wrote:
Hi there,
I have to dynamically create image based on some data stored in
user session. And the question is: how can I do it with Tapestry
4.0? I've tried to find some answers by searching previous posts
but all I find is either Tapestry3-based or I can't see how can I
properly access some persistent (stored in the session) attributes...
One way is to create an Asset and a EngineService. This allows you to
put a link in the html with parameters that can call back into your
page which then streams out the image data (as jpeg, gif, bmp, or
what have you). That is what Howard suggested to me. Its much easier
to do in Tapestry 4.
Basically I have 2 classes and an interface. The following is the
important parts of the classes, if you need more details, let me know
and I will send you the files. This implementation if for Tapestry 4.
It is similar in Tapestry 3 but there is more plumbing one needs to
do. You can see an implementation of a service in the Tapestry
example Workbench in the Chart package.
class ImageAsset implements IAsset {
public ImageAsset(IEngineService aImageService, ImageProvider
aImageProvider, Object [] aParameters) {
imageService = aImageService;
imageProvider = aImageProvider;
parameters = aParameters;
}
...
public String buildURL() {
ILink link = imageService.getLink(false, this);
return link.getURL();
}
...
public static void getImageData(BufferedImage image, WebResponse
response) throws IOException {
...
}
}
class ImageService implements IEngineService {
...
public void service(IRequestCycle cycle) throws IOException {
String pageName = cycle.getParameter(ServiceConstants.PAGE);
String idPath = cycle.getParameter(ServiceConstants.COMPONENT);
IPage page = cycle.getPage(pageName);
IComponent component = page.getNestedComponent(idPath);
try {
((ImageProvider) component).generateImage(response,
linkFactory.extractListenerParameters(cycle));
}
catch (ClassCastException ex) {
exceptionReporter.reportRequestException(
"Component " + component.getExtendedId() + "
does not implement ImageProvider.",
ex);
}
catch (Throwable ex) {
exceptionReporter.reportRequestException("Error creating
Image stream.", ex);
}
}
public ILink getLink(boolean post, Object parameter) {
Defense.isAssignable(parameter, ImageAsset.class, "parameter");
ImageAsset imageAsset = (ImageAsset) parameter;
IComponent component = imageAsset.getComponent();
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put(ServiceConstants.SERVICE, getName());
parameters.put(ServiceConstants.PAGE, component.getPage
().getPageName());
parameters.put(ServiceConstants.COMPONENT,
component.getIdPath());
parameters.put(ServiceConstants.PARAMETER,
imageAsset.getImageParameters());
return linkFactory.constructLink(this, false, parameters,
true);
}
}
interface ImageProvider {
void generateImage(WebResponse response, Object[] parameters) throws
Exception;
}
The ImageAsset class is used by the page to provide a link on the
HTML like
<img jwcid="@Image" image="ognl:workflowImageAsset" title="Workflow"
alt="Workflow" />
The page implements ImageProvider and provides the ImageAsset like so:
@InjectObject("service:App.Image")
public abstract IEngineService getImageService();
public IAsset getWorkflowImageAsset() {
return new ImageAsset(getImageService(), this, new Object[]
{getEvents()});
}
public void generateImage(WebResponse response, Object[]
parameters) throws Exception {
List bmEvents = (List) parameters[0];
try {
BMWorkflow workflow = BMWorkflow.createWorkflow(bmEvents);
BufferedImage image = workflow.createImage(1000, 200);
ImageAsset.getImageData( image, response);
} catch (QueryException e) {
recordError(e);
}
}
And in the hivemodule.xml one puts the service definition
<service-point id="Image"
interface="org.apache.tapestry.engine.IEngineService">
<invoke-factory>
<construct class="image.ImageService">
<set-object property="exceptionReporter"
value="infrastructure:requestExceptionReporter"/>
<set-object property="response"
value="infrastructure:response"/>
<set-object property="linkFactory"
value="infrastructure:linkFactory"/>
</construct>
</invoke-factory>
</service-point>
Hope this helps you on your way.
---
Erik Husby
Senior Software Engineer
Broad Institute of MIT and Harvard
Rm. 2192, 320 Charles St, Cambridge, MA 02141-2023
mobile: 781.354.6669, office: 617.258.9227
email: [EMAIL PROTECTED] AIM: ErikAtBroad