001// Copyright(c) 2015 POSCO ICT
002// Change history
003// 2015-07-10 / 1.1.0 / 
004package com.poscoict.app.job;
005
006import java.lang.management.ManagementFactory;
007import java.lang.reflect.InvocationTargetException;
008import java.lang.reflect.Method;
009import java.sql.Connection;
010import java.sql.PreparedStatement;
011import java.sql.SQLException;
012import java.util.Date;
013import java.util.List;
014import java.util.Map;
015
016import javax.sql.DataSource;
017
018import org.apache.commons.dbcp2.BasicDataSource;
019import org.slf4j.Logger;
020import org.slf4j.LoggerFactory;
021import org.springframework.context.ApplicationContext;
022import org.springframework.context.support.ClassPathXmlApplicationContext;
023import org.springframework.jdbc.datasource.DataSourceUtils;
024import org.springframework.jdbc.support.JdbcUtils;
025
026import com.poscoict.glueframework.biz.control.GlueBizControlConstants;
027import com.poscoict.glueframework.biz.control.GlueBizProvider;
028import com.poscoict.glueframework.context.GlueContext;
029import com.poscoict.glueframework.context.GlueDefaultContext;
030
031/**
032 * Main 클래스.
033 * 
034 * <pre>
035 * java [-option] com.poscoict.app.job.GlueSimpleJob [args..] 
036 * 형태로 GlueSimpleJob 클래스를 실행한다.
037 * 
038 * [args..] 부분의 첫번째는 history id, 두번째는 실행유형, 세번째부터는 사용자 data로 구성한다. 
039 * <xmp>
040 * java [-option] com.poscoict.app.job.GlueSimpleJob -1 ServiceName=job001-service@S userKey=userData@S
041 * java [-option] com.poscoict.app.job.GlueSimpleJob -1 className=sample.job.SamplePgm@S userKey=userData@S
042 * </xmp>
043 * </pre>
044 */
045public class GlueSimpleJob
046{
047    static ApplicationContext applicationContext = null;
048    static Logger logger = LoggerFactory.getLogger( GlueSimpleJob.class );
049
050    public static void main( String args[] )
051    {
052        logger.info( "GlueSimpleJob version : {}", JobConstants.VERSION );
053        boolean isLocalTest = args != null && args.length > 0 && args[0] != null && "-1".equals( args[0] );
054        if ( !isLocalTest )
055        {
056            BasicDataSource dataSource = null;
057            Connection connection = null;
058            try
059            {
060                applicationContext = new ClassPathXmlApplicationContext( "applicationContext-job.xml" );
061                dataSource = applicationContext.getBean( "dataSource", BasicDataSource.class );
062                connection = DataSourceUtils.getConnection( dataSource );
063                String databaseProductName = connection.getMetaData().getDatabaseProductName().toLowerCase();
064                if ( databaseProductName.indexOf( "oracle" ) >= 0 )
065                {
066                    dataSource.addConnectionProperty( "v$session.program", "GlueSimpleJob ver." + JobConstants.VERSION );
067                    // dataSource.addConnectionProperty( "v$session.process", "GlueSimpleJob-java" );
068                    // dataSource.addConnectionProperty( "v$session.terminal", "GlueSimpleJob-terminal" );
069                    // dataSource.addConnectionProperty( "v$session.client_info", "GlueSimpleJob-client" );
070                } else if ( databaseProductName.indexOf( "postgresql" ) >= 0 || databaseProductName.indexOf( "enterprisedb" ) >= 0 )
071                {
072                    dataSource.addConnectionProperty( "ApplicationName", "GlueSimpleJob ver." + JobConstants.VERSION );
073                } else
074                {
075                    logger.warn( "not support adding datasource connection property (application name) - {}", databaseProductName );
076                }
077
078            } catch ( Exception e )
079            {
080                logger.error( "Exception", e );
081                e.printStackTrace();
082                return;
083            } catch ( Throwable t )
084            {
085                logger.error( "Throwable", t );
086                t.printStackTrace();
087                return;
088            } finally
089            {
090                DataSourceUtils.releaseConnection( connection, dataSource );
091            }
092        }
093
094        String name = ManagementFactory.getRuntimeMXBean().getName();
095        String pid = name.substring( 0, name.indexOf( "@" ) );
096        logger.info( "RuntimeMXBean Name : {}, {}", name, pid );
097        if ( logger.isTraceEnabled() )
098        {
099            logger.trace( "BootClassPath : {}", ManagementFactory.getRuntimeMXBean().getBootClassPath() );
100            logger.trace( "ClassPath : {}", ManagementFactory.getRuntimeMXBean().getClassPath() );
101            logger.trace( "LibraryPath : {}", ManagementFactory.getRuntimeMXBean().getLibraryPath() );
102            logger.trace( "ManagementSpecVersion : {}", ManagementFactory.getRuntimeMXBean().getManagementSpecVersion() );
103            logger.trace( "SpecName : {}", ManagementFactory.getRuntimeMXBean().getSpecName() );
104            logger.trace( "SpecVendor : {}", ManagementFactory.getRuntimeMXBean().getSpecVendor() );
105            logger.trace( "SpecVersion : {}", ManagementFactory.getRuntimeMXBean().getSpecVersion() );
106            logger.trace( "StartTime : {}", ManagementFactory.getRuntimeMXBean().getStartTime() );
107            logger.trace( "Uptime : {}", ManagementFactory.getRuntimeMXBean().getUptime() );
108            logger.trace( "VmName : {}", ManagementFactory.getRuntimeMXBean().getVmName() );
109            logger.trace( "VmVendor : {}", ManagementFactory.getRuntimeMXBean().getVmVendor() );
110            logger.trace( "VmVersion : {}", ManagementFactory.getRuntimeMXBean().getVmVersion() );
111            logger.trace( "SystemProperties : {}", ManagementFactory.getRuntimeMXBean().getSystemProperties() );
112            logger.trace( "BootClassPathSupported : {}", ManagementFactory.getRuntimeMXBean().isBootClassPathSupported() );
113            logger.trace( "InputArguments : {}", ManagementFactory.getRuntimeMXBean().getInputArguments() );
114            List<String> arguements = ManagementFactory.getRuntimeMXBean().getInputArguments();
115            for ( String string : arguements )
116            {
117                logger.trace( "InputArgument : {}", string );
118            }
119        }
120        if ( !isLocalTest )
121            GlueSimpleJob.updateStartTime( args[0], pid );
122        long start = System.currentTimeMillis();
123        GlueContext ctx = new GlueDefaultContext();
124        String requestId = null;
125        try
126        {
127            requestId = args[0];
128            if ( logger.isTraceEnabled() )
129            {
130                Map<String, String> env = System.getenv();
131                logger.trace( "{}", env );
132                logger.trace( "" );
133                logger.trace( "{}", System.getProperties() );
134                logger.trace( "" );
135                logger.trace( "" );
136            }
137
138            logger.info( "RequestID:[{}] StartTime[{}]", requestId, new Date( start ) );
139
140            ctx.put( JobConstants.JOB_REQUEST_ID, requestId );
141
142            for ( int i = 1; i < args.length; i++ )
143            {
144                String arg = args[i];
145                logger.trace( "{}", arg );
146                // K:Keyword;S:String;B:boolean;I:Integer;L:Long;D:Double;F:Float
147                if ( arg.contains( "=" ) )
148                {
149                    String s[] = arg.split( "=" );
150                    if ( arg.startsWith( "\"" ) && arg.endsWith( "\"" ) )
151                    {
152                        String tmp = arg.substring( 1, arg.length() - 1 );
153                        logger.trace( "{}", tmp );
154                        s = tmp.split( "=" );
155                    }
156                    if ( s[1].contains( "@" ) )
157                    {
158                        int idx = s[1].lastIndexOf( "@" );
159                        String value = s[1].substring( 0, idx );
160                        if ( s[1].endsWith( "S" ) )
161                        {
162                            ctx.put( s[0], "NULL".equalsIgnoreCase( value ) ? "" : value );
163                        } else if ( s[1].endsWith( "B" ) )
164                        {
165                            ctx.put( s[0], "NULL".equalsIgnoreCase( value ) ? null : Boolean.valueOf( value ) );
166                        } else if ( s[1].endsWith( "I" ) )
167                        {
168                            ctx.put( s[0], "NULL".equalsIgnoreCase( value ) ? null : new Integer( value ) );
169                        } else if ( s[1].endsWith( "L" ) )
170                        {
171                            ctx.put( s[0], "NULL".equalsIgnoreCase( value ) ? null : new Long( value ) );
172                        } else if ( s[1].endsWith( "D" ) )
173                        {
174                            ctx.put( s[0], "NULL".equalsIgnoreCase( value ) ? null : new Double( value ) );
175                        } else if ( s[1].endsWith( "F" ) )
176                        {
177                            ctx.put( s[0], "NULL".equalsIgnoreCase( value ) ? null : new Float( value ) );
178                        }
179                    } else
180                    {
181                        ctx.put( s[0], s[1] );
182                    }
183                } else
184                {
185                    logger.error( "ignore {}", arg );
186                }
187            }
188            logger.info( "{}", ctx );
189
190            if ( ctx.containsKey( GlueBizControlConstants.SERVICE_NAME ) )
191            {
192                try
193                {
194                    GlueBizProvider.getController().doAction( ctx );
195                } catch ( Throwable t )
196                {
197                    if ( ctx.getException() != null )
198                    {
199                        // BeanCreationException 등 GlueService 실행 전에 발생된 에러를 처리하기 위함.
200                        ctx.setException( t );
201                    } else
202                    {
203                        logger.error( "unknwon error", t );
204                    }
205                    t.printStackTrace();
206                }
207            } else if ( ctx.containsKey( "className" ) )
208            {
209                try
210                {
211                    Object clz = Thread.currentThread().getContextClassLoader().loadClass( (String) ctx.get( "className" ) ).newInstance();
212                    Method method = clz.getClass().getMethod( "runProgram", new Class[] { GlueContext.class } );
213                    method.invoke( clz, new Object[] { ctx } );
214                    if ( ctx.getException() != null )
215                    {
216                        logger.error( "UserException", ctx.getException() );
217                        ctx.getException().printStackTrace();
218                    }
219                    // ctx.getException();
220                } catch ( InstantiationException e )
221                {
222                    ctx.setException( e );
223                    logger.error( "InstantiationException", e );
224                } catch ( IllegalAccessException e )
225                {
226                    ctx.setException( e );
227                    logger.error( "IllegalAccessException", e );
228                } catch ( ClassNotFoundException e )
229                {
230                    ctx.setException( e );
231                    logger.error( "ClassNotFoundException", e );
232                } catch ( SecurityException e )
233                {
234                    ctx.setException( e );
235                    logger.error( "SecurityException", e );
236                } catch ( NoSuchMethodException e )
237                {
238                    ctx.setException( e );
239                    logger.error( "NoSuchMethodException", e );
240                } catch ( IllegalArgumentException e )
241                {
242                    ctx.setException( e );
243                    logger.error( "IllegalArgumentException", e );
244                } catch ( InvocationTargetException e )
245                {
246                    ctx.setException( e );
247                    logger.error( "InvocationTargetException", e );
248                } catch ( Throwable t )
249                {
250                    ctx.setException( t );
251                    logger.error( "UserException", t );
252                }
253            } else
254            {
255                ctx.setException( new Exception( "Service is Null!" ) );
256                logger.info( "Service is Null!" );
257            }
258
259        } catch ( Exception e )
260        {
261            logger.error( "Exception", e );
262            e.printStackTrace();
263        } catch ( Throwable t )
264        {
265            logger.error( "Throwable", t );
266            t.printStackTrace();
267        } finally
268        {
269            long end = System.currentTimeMillis();
270            if ( !isLocalTest )
271                GlueSimpleJob.updateEndTime( args[0], end - start, ctx.getException() );
272            logger.info( "RequestID:[{}] EndTime[{}] RunTime:[{}]", requestId, new Date( end ), end - start );
273        }
274        System.exit( 0 );
275    }
276
277    private static void updateEndTime( String id, long runtime, Throwable throwable )
278    {
279        try
280        {
281            if ( "-1".equals( id ) )
282            {
283                return;
284            }
285            DataSource ds = applicationContext.getBean( "dataSource", DataSource.class );
286            logger.debug( "{}", JobConstants.SQL_PGM_END );
287            logger.trace( "{}", runtime );
288            logger.trace( "{}", throwable == null ? "END" : "ERROR" );
289            logger.trace( "{}", id );
290            Connection con = null;
291            PreparedStatement ps = null;
292            con = DataSourceUtils.getConnection( ds );
293            try
294            {
295                ps = con.prepareStatement( JobConstants.SQL_PGM_END );
296                ps.setObject( 1, runtime );
297                ps.setObject( 2, throwable == null ? "END" : "ERROR" );
298                ps.setObject( 3, new Long( id ) );
299                ps.executeUpdate();
300                con.commit();
301            } catch ( SQLException e )
302            {
303                logger.error( "fail to executeUpdate", e );
304            } finally
305            {
306                JdbcUtils.closeStatement( ps );
307                DataSourceUtils.releaseConnection( con, ds );
308            }
309        } catch ( Exception e )
310        {
311            logger.error( "fail to getConnection", e );
312        } catch ( Throwable t )
313        {
314            logger.error( "fail to getConnection", t );
315        }
316    }
317
318    private static void updateStartTime( String id, String pid )
319    {
320        try
321        {
322            if ( "-1".equals( id ) )
323            {
324                return;
325            }
326            DataSource ds = applicationContext.getBean( "dataSource", DataSource.class );
327            logger.debug( "{}", JobConstants.SQL_PGM_START );
328            logger.trace( "{}", "RUNNING" );
329            logger.trace( "{}", pid );
330            logger.trace( "{}", id );
331
332            Connection con = null;
333            PreparedStatement ps = null;
334            con = DataSourceUtils.getConnection( ds );
335            try
336            {
337                ps = con.prepareStatement( JobConstants.SQL_PGM_START );
338                ps.setObject( 1, "RUNNING" );
339                ps.setObject( 2, new Integer( pid ) );
340                ps.setObject( 3, new Long( id ) );
341                ps.executeUpdate();
342                con.commit();
343            } catch ( SQLException e )
344            {
345                logger.error( "fail to executeUpdate", e );
346            } catch ( Exception e )
347            {
348                logger.error( "fail to getConnection", e );
349            } catch ( Throwable t )
350            {
351                logger.error( "fail to getConnection", t );
352            } finally
353            {
354                JdbcUtils.closeStatement( ps );
355                DataSourceUtils.releaseConnection( con, ds );
356            }
357        } catch ( Exception e )
358        {
359            logger.error( "fail to getConnection", e );
360        } catch ( Throwable t )
361        {
362            logger.error( "fail to getConnection", t );
363        }
364    }
365}