java应用中如何捕抓SAS存储过程输出的流信息

java应用中如何捕抓SAS存储过程输出的流信息

 

这个指南演示如何在存储过程中使用ods格式化输出流并被用某种语言编写的应用所接收,如java语言

 

例子报告

首先我们引用一个简单例子,其用ods格式化输出2html报表,由于其使用的是sashelp中的数据,故下面例子你可以直接运行在你的环境中,例子如下

 

l       注:宏 ®ION 用于指示取数据的一个子集

%let REGION=Pacific;

ods html body="shoe_sales.html";

title Shoe Sales by Subsidiary;

title2 Region: ®ION;

proc report data=sashelp.shoes(where=(region="®ION")) nowd;

    column subsidiary sales;

    define subsidiary / group;

    define sales / analysis sum;

run;

title Shoe Sales Detail;

title2 Region: ®ION;

proc report data=sashelp.shoes(where=(region="®ION")) nowd;

    column subsidiary product stores sales;

    define subsidiary / order;

    define product / order;

    define sales / analysis sum;

run;

ods html close;

 

转换上面例子报告到存储过程

只需要下面3个简单步骤就可以

1、  每一个存储过程应该有一个标志用来指示其是存储过程,如下行,该行应该在%let 第一个ods输出之间

*ProcessBody;

2、  转换宏符号作为存储过程的参数,如下

%global REGION;

3、  我们应该初始化ods的开始和结束句子,在存储过程中,我们可以使用下面宏帮助我们自动初始化

%stpbegin

%stpend

 

改后的代码如下:

%global REGION;

*ProcessBody;

%stpbegin;

title Shoe Sales by Subsidiary;

title2 Region: ®ION;

proc report data=sashelp.shoes(where=(region="®ION")) nowd;

    column subsidiary sales;

    define subsidiary / group;

    define sales / analysis sum;

run;

title Shoe Sales Detail;

title2 Region: ®ION;

proc report data=sashelp.shoes(where=(region="®ION")) nowd;

    column subsidiary product stores sales;

    define subsidiary / order;

    define product / order;

    define sales / analysis sum;

run;

%stpend;

调用存储过程

 

我们把该后的程序部署到存储过程服务器上去

 

一旦部署完成,我们就可以使用外部工具来访问该存储过程,如用excel (需要装Add-In for Microsoft Office)

 

当然,也可以通过浏览器来访问该存储过程

 

 

java调用存储过程

 

你可以使用SAS IT APIS 来调用存储过程,你甚至可以使用SAS8.2来完成这一步骤

在开始写java代码前,我们应该明白下面概念

Integrated Object Model (IOM) 是我们远端调用SASAPI.

当我们连接到SAS时,我们将从SAS会话中获得workspace对象.

然后我们从Workspace.中取得其他服务对象

 

简单的java代码

要调用一个存储过程,你应该包含一个  IStoredProcessService 对象的引用并告诉它:

repository 位置,它是一个定位存储过程的目录路径,格式如 "file:/some/directory".  如果我们异步调用存储过程,那java将不会等待存储过程执行完

存储过车文件的名字

存储过程参数,如"name1=value1 name2=value2 …"

 

下面通过java定义了一个方法,用于设置且执行存储过程,代码如下:

 

executeImpl方法

 

private SocketListener executeImpl(

        String stpName, 

        Properties params, 

        IWorkspace workspace) 

throws IOException, GenericError

{

    // create a socket for SAS to send result stream

    // SocketListener is an AppDev Studio utility

    SocketListener socket = new SocketListener();

    int port = socket.setup();

    socket.start();

 

    // get IOM objects from Workspace

    ILanguageService languageService = workspace.LanguageService();

    IStoredProcessService stpService = 

    languageService.StoredProcessService();

 

    // get stored process call info

    String repository =     

        LocalEnvironment.getProperty("stp.repository");

    String stpParams = buildParamString(params);

    Log.debug("repository = "+repository);

    Log.debug("stpName = "+stpName);

    Log.debug("stpParams = "+stpParams);

 

    // define fileref for socket and issue startup statements

    initWorkspace(languageService, port);

    // call stored process

    stpService.Repository(repository);

    languageService.Async(false);

    Log.debug("calling stp");

    stpService.Execute(stpName, stpParams);

    

    // send SAS log to web app log

    Log.debug("checking log");

    dumpLog(languageService);

    return socket;

}    

 

在上面的代码中,使用了下面3iom的接口

IWorkspace, ILanguageService, IStoredProcessService

 

SocketListener类用于监听SAS输出信息,通过端口号和SAS建立联络

 

该类还使用了2个实用类

LocalEnvironment 类用于环境信息初始和输出

Log类用于简单的记录输出

 

其他有用的方法,我们将在下面列出

绑定参数字符串

一个存储过程可以接收0个或者多个参数,如下

private String buildParamString(Properties params)

{

    StringBuffer paramBuff = new StringBuffer();

    Iterator iter = params.keySet().iterator();

    while (iter.hasNext())

    {

        String key = (String) iter.next();

        paramBuff.append(key);

        paramBuff.append('=');

        paramBuff.append('/"');

        paramBuff.append(params.getProperty(key));

        paramBuff.append('/"');

        paramBuff.append(' ');

    }

    String stpParams = paramBuff.toString();

    return stpParams;

}

 

初始化SAS会话

如同通过api直接调用存储过程,SAS本身不知道是如何输出到指定的socket端口中取,而在默认情况下会输出到_webout中取,故我们可以在初始化时分配好_webout并指向指定的socket端口

 

private void initWorkspace(ILanguageService languageService, int port) 

throws IOException, GenericError

{

    // create fileref to my server socket

    // CHEAT ALERT: using localhost as host name for socket!

    StringBuffer block = new StringBuffer();

    block.append("filename _WEBOUT SOCKET ");

    block.append('/'');

    block.append("localhost");

    block.append(':');

    block.append(port);

    block.append('/'');

    block.append(';');

    block.append("/n");

 

    String startupStatement = 

        LocalEnvironment.getProperty("stp.startupStatement");

    if (startupStatement != null)

        block.append(startupStatement);

    

    Log.debug("submitting "+block.toString());

    languageService.Submit(block.toString());

}

 

获得SAS输出日志

直接调用languageServiceflushlog方法可以及时地把日志输出

 

private void dumpLog(ILanguageService languageService)

throws GenericError

{

    int count = 0;

    String log = null;

    Log.sas("/nLOG START/n/n");

    do 

    {

        log = languageService.FlushLog(BUFFSIZE);

        Log.sas(log);

        count++;

    }

    while (log.length() == BUFFSIZE);

Log.sas("/nLOG END (" + count + ")/n");

}

 

 

 

 

 

你可能感兴趣的:(SAS,SAS,第三方开发专栏)