第十五章 高级特性-开放源码:BIRT报表服务器部署及集群支持(续2)

15.2 BIRT报表服务器部署及集群支持

BIRT报表在部署的时候,可能会报出如下的错误:

java.lang.NoSuchMethodError: org.mozilla.javascript.Context.enter(Lorg/mozilla/javascript/Context;Lorg/mozilla/javascript/ContextFactory;)Lorg/mozilla/javascript/Context;
	at org.mozilla.javascript.ContextFactory.enterContext(ContextFactory.java:588)
	at org.mozilla.javascript.ContextFactory.enterContext(ContextFactory.java:551)
	at org.eclipse.birt.report.model.simpleapi.ReportDesign.initFunctions(ReportDesign.java:368)
	at org.eclipse.birt.report.model.simpleapi.ReportDesign.(ReportDesign.java:82)
	at org.eclipse.birt.report.model.simpleapi.ElementUtil.getElement(ElementUtil.java:59)
	at org.eclipse.birt.report.model.api.impl.SimpleElementFactory.getElement(SimpleElementFactory.java:279)
	at org.eclipse.birt.report.engine.executor.ExecutionContext.registerDesign(ExecutionContext.java:1345)
	at org.eclipse.birt.report.engine.executor.ExecutionContext.initializeScriptContext(ExecutionContext.java:375)
	at org.eclipse.birt.report.engine.executor.ExecutionContext.getScriptContext(ExecutionContext.java:1088)
	at org.eclipse.birt.report.engine.executor.ExecutionContext.compile(ExecutionContext.java:762)
	at org.eclipse.birt.report.engine.executor.ExecutionContext.evaluate(ExecutionContext.java:696)
	at org.eclipse.birt.report.engine.script.internal.ScriptExecutor.handleScriptInternal(ScriptExecutor.java:61)
	at org.eclipse.birt.report.engine.script.internal.ScriptExecutor.handleScript(ScriptExecutor.java:48)
	at org.eclipse.birt.report.engine.script.internal.ReportScriptExecutor.handleInitialize(ReportScriptExecutor.java:44)
	at org.eclipse.birt.report.engine.api.impl.EngineTask.loadDesign(EngineTask.java:1766)
	at org.eclipse.birt.report.engine.api.impl.RunAndRenderTask.doRun(RunAndRenderTask.java:98)
	at org.eclipse.birt.report.engine.api.impl.RunAndRenderTask.run(RunAndRenderTask.java:77)
	at com.vandagroup.birt.ReportServlet.doGet(ReportServlet.java:152)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
	at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
	at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
	at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
	at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
	at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3594)
	at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
	at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121)
	at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2202)
	at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2108)
	at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1432)
	at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
	at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)

这是什么原因呢?明明js.jar就在lib中,为什么找不到类找不到方法呢?

熟悉weblogic的人一下子就可能明白,这是类库冲突。类在加载的时候,不同路径下的同一个类,如果加载优先级相同时会导致类加载失败。

解决的方式有很多,网上一直盛传的是设置环境变量,或者利用weblogic的配置标签

更改标签的方法是在 web应用中加入
<prefer-web-inf-classes>true</prefer-web-inf-classes>

更改环境变量的方法是,改写setDomainEnv.bash, 更改如下:
CLASSPATH=“{WL_HOME}/server/lib/js.jar {CLASSPATH}"
将js.jar 文件复制到 server/lib目录中。在类路径中设置优先载入。
不过这两种方式在集群环境中还是会失败。

那么就修改weblogic.jar吧,替换其中的js.jar的那一部分即可。

由于birt最新版的提供了导航栏,工具栏等特性,这些特性为单服务器环境下的部署使用提供了便利,但在集群环境中没有考虑到session复制的问题。这种情况下,我们可以自己定制web birt,具体的书写参考

第十三章 BIRT报表引擎API及报表API (续2)-利用BIRT设计引擎API生成报表

在这种情况下,就可以按照我们平常的方式来定制session失效时间

<weblogic-web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-web-app      
http://www.bea.com/ns/weblogic/weblogic-web-app/1.0/weblogic-web-app.xsd"    
                       xmlns="http://www.bea.com/ns/weblogic/weblogic-web-app">     
    <container-descriptor>   
        <prefer-web-inf-classes>true</prefer-web-inf-classes>   
    </container-descriptor>   
</weblogic-web-app>  

 

<session-config>
         <session-timeout>180</session-timeout>
</session-config>

尽管birtviewer和工具栏,导航栏接管了session,但birt提供了源码以供定制,如果用户基础扎实,还是能通过修改源码复制session,最重要的类是抽象类AbstractBaseFragment此类是实现了接口IFragment,并且实现了部分方法比如Service(HttpServletRequest request,HttpServletResponse response)方法,里面分别调用doPreService ( request, response ),doService ( request, response )和doPostService ( request, response )3个方法,其中doPostService(request,response)是抽象方法,需要继承它的类去实现的,callBack ( HttpServletRequest request,HttpServletResponse response )是回传用的,里面进行了一个判断,判断当前的list容器里面有没有Fragment的实例,有的话再次取的实例,调用该实例的service方法,而容器里面的Fragment是通过addChild(IFragment)添加进去的其他还有设置和取的jsp的路径,标题等.

这里面包含了众多的布局类和对话框类,其中布局类中有一个非常重要的类EngineFragment,继承至BirtBaseFragment,重写了doPreService,doService,doPostService方法,这里面主要是想通过engine的API来操作报表,直接保存或者输出打印

/**
	 * Anything before do service.
	 * 
	 * @param request
	 *            incoming http request
	 * @param response
	 *            http response
	 * @exception ServletException
	 * @exception IOException
	 */
	protected void doPreService( HttpServletRequest request,
			HttpServletResponse response ) throws ServletException, IOException
	{
		String format = ParameterAccessor.getFormat( request );
		String openType = ParameterAccessor.getOpenType( request );
		if ( IBirtConstants.SERVLET_PATH_DOWNLOAD.equalsIgnoreCase( request
				.getServletPath( ) ) )
		{
			response.setContentType( "text/plain; charset=utf-8" ); //$NON-NLS-1$
			response
					.setHeader(
							"Content-Disposition", "attachment; filename=exportdata.csv" ); //$NON-NLS-1$ //$NON-NLS-2$
		}
		else if ( IBirtConstants.SERVLET_PATH_DOCUMENT
				.equalsIgnoreCase( request.getServletPath( ) ) )
		{
			// generate document file from report design file.
			BaseAttributeBean attrBean = (BaseAttributeBean) request
					.getAttribute( IBirtConstants.ATTRIBUTE_BEAN );
			String docFile = attrBean.getReportDocumentName( );
			if ( docFile == null || docFile.length( ) <= 0 )
			{
				String fileName = ParameterAccessor
						.generateFileNameWithoutExtension( attrBean
								.getReportDesignName( ) )
						+ "." + IBirtConstants.SUFFIX_DESIGN_DOCUMENT; //$NON-NLS-1$
				// output rptdocument file
				response.setContentType( "application/octet-stream" ); //$NON-NLS-1$
				response
						.setHeader(
								"Content-Disposition", "attachment; filename=" + fileName ); //$NON-NLS-1$ //$NON-NLS-2$				
			}
			else
			{
				response.setContentType( "text/html; charset=utf-8" ); //$NON-NLS-1$
			}
		}
		else
		{
			if ( ParameterAccessor.PARAM_FORMAT_PDF.equalsIgnoreCase( format ) )
			{
				response.setContentType( "application/pdf" ); //$NON-NLS-1$
			}
			else
			{
				String mimeType = ReportEngineService.getInstance( )
						.getMIMEType( format );
				if ( mimeType != null && mimeType.length( ) > 0 )
					response.setContentType( mimeType );
				else
					response.setContentType( "application/octet-stream" ); //$NON-NLS-1$
			}

			if ( !ParameterAccessor.isGetImageOperator( request ) )
			{
				String filename = ParameterAccessor.generateFileName( request,
						format );
				response
						.setHeader(
								"Content-Disposition", openType + "; filename=\"" + filename + "\"" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
			}
		}
	}

	/**
	 * Render the report in html/pdf format by calling engine service.
	 * 
	 * @param request
	 *            incoming http request
	 * @param response
	 *            http response
	 * @exception ServletException
	 * @exception IOException
	 */
	protected void doService( HttpServletRequest request,
			HttpServletResponse response ) throws ServletException, IOException
	{
		BaseAttributeBean attrBean = (BaseAttributeBean) request
				.getAttribute( IBirtConstants.ATTRIBUTE_BEAN );

		OutputStream out = response.getOutputStream( );
		GetUpdatedObjectsResponse upResponse = new GetUpdatedObjectsResponse( );
		IContext context = new BirtContext( request, response );
		Operation op = null;
		try
		{
			if ( IBirtConstants.SERVLET_PATH_DOWNLOAD.equalsIgnoreCase( request
					.getServletPath( ) ) )
			{
				BirtExtractDataActionHandler extractDataHandler = new BirtExtractDataActionHandler(
						context, op, upResponse );
				extractDataHandler.execute( );
			}
			else if ( IBirtConstants.SERVLET_PATH_DOCUMENT
					.equalsIgnoreCase( request.getServletPath( ) ) )
			{
				String docFile = attrBean.getReportDocumentName( );
				if ( docFile == null || docFile.length( ) <= 0 )
				{
					// generate the temp document file
					docFile = ParameterAccessor.getReportDocument( request,
							"", true ); //$NON-NLS-1$
					attrBean.setReportDocumentName( docFile );
					BirtRunReportActionHandler runReport = new BirtRunReportActionHandler(
							context, op, upResponse );
					runReport.execute( );

					// output rptdocument file
					BirtUtility.outputFile( docFile, out, true );
				}
				else
				{
					BirtRunReportActionHandler runReport = new BirtRunReportActionHandler(
							context, op, upResponse );
					runReport.execute( );
					BirtUtility
							.writeMessage(
									out,
									BirtResources
											.getMessage( "birt.viewer.message.document.successful" ), //$NON-NLS-1$
									IBirtConstants.MSG_COMPLETE );
				}
			}
			else if ( ParameterAccessor.isGetImageOperator( request ) )
			{
				BirtRenderImageActionHandler renderImageHandler = new BirtRenderImageActionHandler(
						context, op, upResponse );
				renderImageHandler.execute( );
			}
			else
			{
				// if use OUTPUT pattern, it will generate document from report
				// design file
				if ( IBirtConstants.SERVLET_PATH_OUTPUT
						.equalsIgnoreCase( request.getServletPath( ) ) )
				{
					File file = new File( attrBean.getReportDocumentName( ) );
					if ( !file.exists( ) )
					{
						BirtRunReportActionHandler handler = new BirtRunReportActionHandler(
								context, op, upResponse );
						handler.execute( );
					}

					file = new File( attrBean.getReportDocumentName( ) );
					if ( !file.exists( ) )
					{
						AxisFault fault = new AxisFault( );
						fault
								.setFaultReason( BirtResources
										.getMessage( ResourceConstants.ACTION_EXCEPTION_NO_REPORT_DOCUMENT ) );
						throw fault;
					}
					else
					{
						// If document isn't completed, throw Exception
						if ( attrBean.isDocumentProcessing( ) )
						{
							AxisFault fault = new AxisFault( );
							fault
									.setFaultReason( BirtResources
											.getMessage( ResourceConstants.GENERAL_EXCEPTION_DOCUMENT_FILE_PROCESSING ) );
							throw fault;
						}
					}
					
					attrBean.setDocumentInUrl( true );
				}

				// Print report on server
				boolean isPrint = false;
				if ( IBirtConstants.ACTION_PRINT.equalsIgnoreCase( attrBean
						.getAction( ) ) )
				{
					isPrint = true;
					out = new ByteArrayOutputStream( );
				}

				if ( ParameterAccessor.isGetReportlet( request ) )
				{
					BirtGetReportletActionHandler getReportletHandler = new BirtGetReportletActionHandler(
							context, op, upResponse, out );
					getReportletHandler.execute( );
				}
				else if ( attrBean.isDocumentInUrl( ) )
				{
					BirtRenderReportActionHandler runReportHandler = new BirtRenderReportActionHandler(
							context, op, upResponse, out );
					runReportHandler.execute( );
				}
				else
				{
					BirtRunAndRenderActionHandler runAndRenderHandler = new BirtRunAndRenderActionHandler(
							context, op, upResponse, out );
					runAndRenderHandler.execute( );
				}

				if ( isPrint )
				{
					InputStream inputStream = new ByteArrayInputStream(
							( (ByteArrayOutputStream) out ).toByteArray( ) );
					BirtUtility.doPrintAction( inputStream, request, response );
				}
			}
		}
		catch ( RemoteException e )
		{
			// if get image, don't write exception into output stream.
			if ( !ParameterAccessor.isGetImageOperator( request ) )
			{
				response.setContentType( "text/html; charset=utf-8" ); //$NON-NLS-1$
				BirtUtility.appendErrorMessage( response.getOutputStream( ), e );
			}
		}
	}

	/**
	 * Override implementation of doPostService.
	 */
	protected String doPostService( HttpServletRequest request,
			HttpServletResponse response ) throws ServletException, IOException
	{
		return null;
  	}

布局类FramesetFragment,RunFragment和上面的类似。
参数类主要是处理参数,参数基类ScalarParameterFragment,继承至BirtBaseFragment,重写了doService,doPostService方法,这里面不多说了,这里引入了一个参数定义类ParameterDefinition上下文类:BaseContext抽象类,实现了IContext接口,这里面主要有一个是ThreadLocal类的引入,ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。归纳了两点:
1、每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
2、将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行
的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。还有就是在通过构造函数初始化的时候设置了这个上下文变量
public BaseContext( HttpServletRequest request, HttpServletResponse response )
{

this.request = request;

this.response = response;

__init( );

contextTraker.set( this );

}

在这儿仅仅列举了session如何保持,页面如何响应显示报表和下载打印报表。至于页面如何处理分页,如何处理参数输入,认真阅读BIRT报表提供的viewer工具栏,导航栏源码,有助于理解BIRT API的运行机制。


 


您的回应...

相关话题

查看全部

也许你感兴趣

换一批

热门标签

更多