【笔记】【Informatica】自定义序列生成器组件

/**************************************************************************
 *
 * Copyright (c) 2003 Informatica Corporation.  This file contains
 * material proprietary to Informatica Corporation and may not be copied
 * or distributed in any form without the written permission of Informatica
 * Corporation
 *
 **************************************************************************/

/**************************************************************************
 * Custom Transformation p_GetSeqVal Procedure File
 *
 * This file contains code that functions that will be called by the main
 * server executable.
 *
 * For more information on these files,
 * see $(PM_HOME)/ExtProc/include/Readme.txt
 **************************************************************************/

/**************************************************************************
                               Includes
 **************************************************************************/

#include "p_GetSeqVal.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <stdarg.h>
#include <process.h>

/**************************************************************************
                               UserDefineMacro
 **************************************************************************/

#define DLLNAME "SeqGenerator.dll"
#define PMDTM "pmdtm.exe"
#define EXTPROCDIR "ExtProc\\"
#define SEQFILE "SeqGenerator.tsv"
#define LOCKFILE "SeqGenerator.lock"
#define SEQNAMELEN 100
#define MAXSEQNUM 10000
typedef unsigned long int seqval_t;
#define MSGCHARS 1000
#define MAX_LINE_SIZE 1000
#define MSGMARK ">>>>>>>>>>>>>>>"
#define PROCNAME "SeqGenerator"

/**************************************************************************
                               SharedVariables
 **************************************************************************/

struct seq_t{
	char chSeqName[SEQNAMELEN+1];
	seqval_t nSeqVal;
};

struct seqlist_t{
	struct seq_t arrSequences[MAXSEQNUM];
	int nSeqNums;
};

#pragma data_seg("SeqGeneratorShared")
static int nInitFlag=0;
static int nRefCount=0;
static struct seqlist_t strSeqList={0};
#pragma data_seg()

#pragma comment(linker,"/section:SeqGeneratorShared,rws") 

/**************************************************************************
                               Debug switch
 **************************************************************************/

//#define DEBUG_MODE

#ifdef DEBUG_MODE
    //LogMessage("%s DebugLog:",MSGMARK);
#endif

/**************************************************************************
                               Global Variables
 **************************************************************************/

char chLogMsg[MSGCHARS],chMutexName[MSGCHARS];
TCHAR szPath[MAX_PATH],dllDir[MAX_PATH],SeqFilePath[MAX_PATH],LockFilePath[MAX_PATH];
FILE *fpSeqFile,*fpLockFile;
char *rowSeqName;
char chSeqName[SEQNAMELEN+1];
seqval_t nSeqVal;
struct seqcache_t{
	char chSeqName[SEQNAMELEN+1];
	seqval_t *ptrSeqVal;
};

struct seqlistcache_t{
	struct seqcache_t arrSequences[MAXSEQNUM];
	int nSeqNums;
};
struct seqlistcache_t strSeqListCache={0};
//HANDLE hMutex;

/**************************************************************************
                               Functions
 **************************************************************************/

int LogMessage(char *fmt,...){
    va_list ptrArg;
	va_start(ptrArg,fmt);
	vsprintf(chLogMsg,fmt,ptrArg);
	va_end(ptrArg);
	INFA_CTLogMessageM( eESL_LOG,chLogMsg);
	return 0;
}

int GetFileNumRows(FILE* fp){   
    int i = 0;
    char strLine[MAX_LINE_SIZE];
    fseek(fp,0,SEEK_SET);
    while (fgets(strLine, MAX_LINE_SIZE, fp))
        i++;
    fseek(fp,0,SEEK_SET);
    return i;
}

char * left(char *dst,char *src, int n){
    char *p = src;
    char *q = dst;
    int len = strlen(src);
    if(n>len) n = len;
    while(n--) *(q++) = *(p++);
    *(q++)='\0'; 
    return dst;
}

char * mid(char *dst,char *src, int n,int m) {
    char *p = src;
    char *q = dst;
    int len = strlen(src);
    if(m>len) m = len-n; 
    if(n<0) n=0;  
    if(n>len) return NULL;
    p += n;
    while(m--) *(q++) = *(p++);
    *(q++)='\0'; 
    return dst;
}

/*
INFA_STATUS mGetMutex(){
    while(1){
	    hMutex=CreateMutex(NULL,FALSE,PROCNAME);
		if(hMutex&&GetLastError()==ERROR_ALREADY_EXISTS){
		    if(hMutex!=NULL){
			    CloseHandle(hMutex);
			}
			Sleep(1000);
			continue;
		} 
		else if(hMutex!=NULL){
		    break;
		}
		else {
			return INFA_FAILURE;
		}
	}
	return INFA_SUCCESS;
}
*/

/**************************************************************************
   Function: p_GetSeqVal_procInit

 Description: Initialization for the procedure.  Returns INFA_SUCCESS if 
 procedure initialization succeeds, else return INFA_FAILURE.

 Input: procedure - the handle for the procedure
 Output: None
 Remarks: This function will get called once for the session at
 initialization time.  It will be called after the moduleInit function.
 **************************************************************************/

INFA_STATUS p_GetSeqVal_procInit( INFA_CT_PROCEDURE_HANDLE procedure)
{
	//Sleep(10000);
    INFA_CTChangeStringMode( procedure, eASM_MBCS );
	if( !GetModuleFileName( NULL, szPath, MAX_PATH ) ){
        LogMessage("GetModuleFileName failed (%d)\n", GetLastError());
        return INFA_FAILURE;
	} else {
		LogMessage("ModuleFileName is : %s\n", szPath);

		mid(dllDir,szPath,0,strlen(szPath)-strlen(PMDTM));
		strcat(dllDir,EXTPROCDIR);
		LogMessage("ModuleDirectory is : %s\n", dllDir);

		strcpy(SeqFilePath,dllDir);
		strcat(SeqFilePath,SEQFILE);
		LogMessage("Sequence File is : %s\n", SeqFilePath);

		strcpy(LockFilePath,dllDir);
		strcat(LockFilePath,LOCKFILE);
		LogMessage("Lock File is : %s\n", LockFilePath);
	}
	//CreateMutex(NULL,FALSE,PROCNAME);
	//mGetMutex();
	//WaitForSingleObject(hMutex, INFINITE);
	fpLockFile=fopen(LockFilePath,"w");
	while(LockFile(fpLockFile,1,1,1,1)!=0){
		Sleep(2000);
	}
	if(1==++nRefCount){
		int nFileNumRows,i;
        LogMessage("%s Loading Sequence File\n",MSGMARK);
        fpSeqFile=fopen(SeqFilePath,"a+");
        nFileNumRows=GetFileNumRows(fpSeqFile);
		LogMessage("%s Sequence Objects Nums: %d\n",MSGMARK,nFileNumRows);
		strSeqList.nSeqNums=0;
		for(i=0;i<nFileNumRows;i++){
			fscanf(fpSeqFile,"%s\t%lu\n",chSeqName,&nSeqVal);
			strSeqList.nSeqNums++;
			strcpy(strSeqList.arrSequences[i].chSeqName,chSeqName);
			strSeqList.arrSequences[i].nSeqVal=nSeqVal;
		}
		if(EOF==fclose(fpSeqFile)){
		    LogMessage("Close Sequence File Failed!\n" );
		    return INFA_FAILURE;
	    }
		nInitFlag=1;
		//CloseHandle(hMutex);
		LogMessage("%s Finish loading Sequence File",MSGMARK);
	} else {
		LogMessage("%s Wait for loading Sequence File",MSGMARK);
		while(1!=nInitFlag){
		}
		LogMessage("%s Finish loading Sequence File",MSGMARK);
	}
	UnlockFile(fpLockFile,1,1,1,1);
	if(EOF==fclose(fpLockFile)){
        LogMessage("Close Lock File Failed!\n" );
		return INFA_FAILURE;
	}
	//ReleaseMutex(hMutex);

	
    return INFA_SUCCESS;
}


/**************************************************************************
   Function: p_GetSeqVal_procDeinit

 Description: Deinitialization for the procedure.  Returns INFA_SUCCESS if 
 procedure deinitialization succeeds, else return INFA_FAILURE.

 Input: procedure - the handle for the procedure
 Output: None
 Remarks: This function will get called once for the session at
 deinitialization time.  It will be called before the moduleDeinit
 function.
 **************************************************************************/

INFA_STATUS p_GetSeqVal_procDeinit( INFA_CT_PROCEDURE_HANDLE procedure, INFA_STATUS sessionStatus )
{
	//mGetMutex();
	//WaitForSingleObject(hMutex, INFINITE);
	fpLockFile=fopen(LockFilePath,"w");
	while(LockFile(fpLockFile,1,1,1,1)!=0){
		Sleep(2000);
	}
	if(0==--nRefCount){
		int i;
		LogMessage("%s Writing Sequence File",MSGMARK);
		fpSeqFile=fopen(SeqFilePath,"w");
		for(i=0;i<strSeqList.nSeqNums;i++){
			fprintf(fpSeqFile,"%s\t%lu\n",strSeqList.arrSequences[i].chSeqName,strSeqList.arrSequences[i].nSeqVal);
		}
		if(EOF==fclose(fpSeqFile)){
			LogMessage("Close Sequence File Failed!\n" );
			return INFA_FAILURE;
		}
		LogMessage("%s Finish Writing Sequence File",MSGMARK);
	}
    UnlockFile(fpLockFile,1,1,1,1);
	if(EOF==fclose(fpLockFile)){
        LogMessage("Close Lock File Failed!\n" );
		return INFA_FAILURE;
	}
	//ReleaseMutex(hMutex);
	//CloseHandle(hMutex);
    return INFA_SUCCESS;
}


/**************************************************************************
   Function: p_GetSeqVal_partitionInit

 Description: Initialization for the partition.  Returns INFA_SUCCESS if 
 partition deinitialization succeeds, else return INFA_FAILURE.

 Input: partition - the handle for the partition
 Output: None
 Remarks: This function will get called once for each partition for each
 transformation in the session.
 **************************************************************************/

INFA_STATUS p_GetSeqVal_partitionInit( INFA_CT_PARTITION_HANDLE partition )
{
    /*TODO: fill in code here*/
    return INFA_SUCCESS;
}


/**************************************************************************
   Function: p_GetSeqVal_partitionDeinit

 Description: Deinitialization for the partition.  Returns INFA_SUCCESS if 
 partition deinitialization succeeds, else return INFA_FAILURE.

 Input: partition - the handle for the partition
 Output: None
 Remarks: This function will get called once for each partition for each
 transformation in the session.
 **************************************************************************/

INFA_STATUS p_GetSeqVal_partitionDeinit( INFA_CT_PARTITION_HANDLE partition )
{
    /*TODO: fill in code here*/
    return INFA_SUCCESS;
}


/**************************************************************************
   Function: p_GetSeqVal_inputRowNotification

 Description: Notification that a row needs to be processed for an input
 group in a transformation for the given partition.  Returns INFA_ROWSUCCESS
 if the input row was processed successfully, INFA_ROWERROR if the input
 row was not processed successfully and INFA_FATALERROR if the input row
 causes the session to fail.

 Input: partition - the handle for the partition for the given row
        group - the handle for the input group for the given row
 Output: None
 Remarks: This function is probably where the meat of your code will go,
 as it is called for every row that gets sent into your transformation. 
 **************************************************************************/

INFA_ROWSTATUS p_GetSeqVal_inputRowNotification( INFA_CT_PARTITION_HANDLE partition,
                                    INFA_CT_INPUTGROUP_HANDLE inputGroup )

{
    const INFA_CT_OUTPUTGROUP_HANDLE* outputGroups = NULL;
    const INFA_CT_INPUTPORT_HANDLE* inputGroupPorts = NULL;
    const INFA_CT_OUTPUTPORT_HANDLE* outputGroupPorts = NULL;
    size_t nNumInputPorts = 0, nNumOutputGroups = 0, nNumPortsInOutputGroup = 0;
	int i,j;
	outputGroups = INFA_CTGetChildrenHandles(partition,&nNumOutputGroups,OUTPUTGROUPTYPE);
	outputGroupPorts = INFA_CTGetChildrenHandles(outputGroups[0],&nNumPortsInOutputGroup,OUTPUTPORTTYPE);
	inputGroupPorts = INFA_CTGetChildrenHandles(inputGroup,&nNumInputPorts,INPUTPORTTYPE);

    rowSeqName=(char*)INFA_CTGetDataVoid(inputGroupPorts[0]);

	for(j=0;j<strSeqListCache.nSeqNums;j++){
        if(strcmp(rowSeqName,strSeqListCache.arrSequences[j].chSeqName)==0)
			break;
	}
	if(j==strSeqListCache.nSeqNums){
		for(i=0;i<strSeqList.nSeqNums;i++){
			if(strcmp(rowSeqName,strSeqList.arrSequences[i].chSeqName)==0)
				break;
		}
		if(i==strSeqList.nSeqNums){
			strcpy(strSeqList.arrSequences[i].chSeqName,rowSeqName);
			strSeqList.nSeqNums++;
			strcpy(strSeqListCache.arrSequences[j].chSeqName,rowSeqName);
		    strSeqListCache.arrSequences[j].ptrSeqVal=&(strSeqList.arrSequences[i].nSeqVal);
		    strSeqListCache.nSeqNums++;
		}
		nSeqVal=++(strSeqList.arrSequences[i].nSeqVal);
		strcpy(strSeqListCache.arrSequences[j].chSeqName,rowSeqName);
		strSeqListCache.arrSequences[j].ptrSeqVal=&(strSeqList.arrSequences[i].nSeqVal);
		strSeqListCache.nSeqNums++;
	} else {
		nSeqVal=++*(strSeqListCache.arrSequences[j].ptrSeqVal);
	}
	

    INFA_CTSetData(outputGroupPorts[0], &nSeqVal);
	INFA_CTSetIndicator(outputGroupPorts[0],INFA_DATA_VALID);
    return INFA_CTOutputNotification(outputGroups[0]);
}


/**************************************************************************
   Function: p_GetSeqVal_eofNotification

 Description: Notification that the last row for an input group has already
 been seen.  Return INFA_FAILURE if the session should fail as a result of
 seeing this notification, INFA_SUCCESS otherwise.

 Input: partition - the handle for the partition for the notification
        group - the handle for the input group for the notification
 Output: None
 **************************************************************************/

INFA_STATUS p_GetSeqVal_eofNotification( INFA_CT_PARTITION_HANDLE partition,
                            INFA_CT_INPUTGROUP_HANDLE group)
{
    /*TODO: fill in code here*/
    return INFA_SUCCESS;
}


/**************************************************************************
   Function: p_GetSeqVal_dataBdryNotification

 Description: Notification that a transaction has ended.  The data
 boundary type can either be commit or rollback.
 Return INFA_FAILURE if the session should fail as a result of
 seeing this notification, INFA_SUCCESS otherwise.

 Input: partition - the handle for the partition for the notification
        transactionType - commit or rollback 
 Output: None
 **************************************************************************/

INFA_STATUS p_GetSeqVal_dataBdryNotification ( 
                       INFA_CT_PARTITION_HANDLE partition,
                       INFA_CT_DATABDRY_TYPE transactionType)
{
    /*TODO: fill in code here*/
    return INFA_SUCCESS;
}

  

posted @ 2014-08-22 00:52  Azik  阅读(1012)  评论(0编辑  收藏  举报