IT approaches

воскресенье, 20 апреля 2014 г.

I've came up with a pretty nice solution to realize the Windows Service using Java with help of Apache Commons Daemon. procrun.exe is used in Windows for that approach. It appears this approach is the potential candadate for the best practice so I want to share it with you. And of course I would like you to judge it - please welcome to comment!

ACD allows to use several methoods to execute the java application. For example you can use StartParams and StopParams along with StartClass and StopClass to use one method to start and stop the application - in this case you need to parse the corresponding parameter in the start/stop class to handle the corresponding action. You also can use different methods to execute the application specifying the StartMode and StopMode ... I prefer to use JVM method specifying different methods to start and stop the application.
To implement this I use StartMethod and StopMethod along with StartClass and StopClass to start and stop my service.

To examine and run following examples you need to download the sources from here.

First, to learn the basics let's consider simplified example. To test it extract the archieve, build the maven project (I used maven 3 to assemble it) with "mvn package" command. Copy the resulted JavaWindowsServiceUsingCommonsDaemon-0.0.1-SNAPSHOT.jar to the simpleExample folder. Copy corresponding prunsrvXX.exe from the "bin" folder to the simpleExample too. Run the install_service.bat, check "Services". You should see new "Test Service" here. "logs" folder with couple of files iin it should be created. Now start the service in "Services". Check the console.log - you should detect logs messages dynamically added here.

Here is the RandomLoggerService.java class file to work as the service:

package test.service;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Random;/** A Modified version of Commons Daemon provided sample ProcrunService* The original can be found here* http://svn.apache.org/viewvc/commons/proper/daemon/trunk/src/samples/ProcrunService.java?view=markup*//** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements. See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License. You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.**//*** Sample service implementation for use with Windows Procrun.* <p>* Use the main() method for running as a Java application. Use the* start() and stop() methods for running as a jvm (in-process) service*/public class RandomLoggerService implements Runnable {/** The Constant MS_PER_SEC. */private static final long MS_PER_SEC = 1000L; // Milliseconds in a second/** The logger thread. */private static Thread loggerThread; // start and stop are called// from different threads/** The Constant random. */private static final Random random = new Random();private static final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ");private static void log(String message) {System.out.println(df.format(new Date()) + message);}/*** This method simulates performing the work of the service. In this case, it just logs* a message any time between 1-5 seconds.* A real logging application would get its log messages from a queue or socket etc.*/public void run() {log("Thread started");while (true) {long sleepTime = random.nextInt(4) + 1;try {log("pausing " + sleepTime + " seconds");Thread.sleep(sleepTime * MS_PER_SEC);} catch (InterruptedException e) {log("Exiting");break;}}}/*** Start thread.* */private static void startThread() {log("Starting the thread");loggerThread = new Thread(new RandomLoggerService());loggerThread.start();}/*** Start the jvm version of the service, and waits for it to complete.* * @param args* ignored*/public static void start(String[] args) {startThread();synchronized (loggerThread) {try {loggerThread.wait();} catch (InterruptedException e) {log("'Wait' interrupted: " + e.getMessage());}}}/*** Stop the JVM version of the service.* * @param args* ignored*/public static void stop(String[] args) {if (loggerThread != null) {log("Stopping the thread");loggerThread.interrupt();synchronized (loggerThread) {loggerThread.notify();}} else {log("No thread to interrupt");}}public static void main(String[] args) {// This method isn't used by the Apache Commons Daemon runner, it is defined to have a possibility// to emulate running the same as simple java application e.g. for the debug purposeRuntime.getRuntime().addShutdownHook(new Thread() {public void run() {RandomLoggerService.stop(new String[] {});}});start(args);}}

2 methods are used here by Apache Daemon helper - "start" to start the service and "stop" to stop it. "main" function is given here to use the same class as java main class to have a possibility to run the same what Apache Daemon is doing for the class while it's being run as the service but in the console - to run it as a simple java application mode just run this class in the console.

The install_service.bat batch file to install the service:

rem Note you need to have JAVA_HOME to be set and point to the existed JDK
rem treat this folder as Application Home folder
set APP_HOME=%~dp0
rem remove last "\" from the path to Application Home
for %%F in ("%APP_HOME%") do set APP_HOME=%%~fF
set APP_JAR=%APP_HOME%\JavaWindowsServiceUsingCommonsDaemon-0.0.1-SNAPSHOT.jar
set START_CLASS=test.service.RandomLoggerService
set STOP_CLASS=%START_CLASS%
set START_METHOD=start
set STOP_METHOD=stop
set APP_LOGS_FOLDER=%APP_HOME%\logs
set APP_CONSOLE_LOG=%APP_LOGS_FOLDER%\console.log
if not exist "%APP_LOGS_FOLDER%" md "%APP_LOGS_FOLDER%"
prunsrv.exe //IS//TestService --DisplayName "Test Service" --Description "My Test Service" --LogPath "%APP_LOGS_FOLDER%"^
--Install "%APP_HOME%\prunsrv.exe" --Jvm "%JAVA_HOME%\jre\bin\server\jvm.dll" --StartPath "%APP_HOME%" --StopPath "%APP_HOME%"^
--Classpath "%APP_JAR%" --StartClass %START_CLASS% --StopClass %STOP_CLASS% --StartMethod %START_METHOD% --StopMethod %STOP_METHOD%^
--StartMode jvm --StopMode jvm --StdOutput "%APP_CONSOLE_LOG%" --StdError "%APP_CONSOLE_LOG%"

Here is close to minimum set of settings in this batch file. As I've said previously "method" specification is used to setup the access to Service handler. So "start" method is used to start the service, per Daemon documentation it must not exit until the seervice should run. "stop" method is to stop the service. To uninstall the service use the uninstall_service.bat.

Now let's switch to the most interesting set of batch files in "bin" folder - copy the same prunmgr.exe and JavaWindowsServiceUsingCommonsDaemon-0.0.1-SNAPSHOT.jar to that folder. Install the service using the similar batch file. It installs the service and configures it using the update_config.bat call. This file is intended to update the service configuration any time you need to change it. Just edit the update_config.bat and run it once. After that you need to (re)start the service for settings to take effect. Settings are stored in the registry. So next time when you are starting the service again they are retaken from there. E.g. you can uncomment the string setting the remote debugging ("-Xdebug" etc.) and after you restart the service you can access it to perform the remote debugging.
You can also use config_manager.bat to execute the UI tool allowing to edit the service settings in the dialog box. To apply these changes you also need to restart the service for settings to take effect. Note that if you run update_config.bat again after it will reset all parameters to the state kept in this batch file.run_in_console.bat allows to run your service application in the console mode. You may find necessary to stop the same service to avoid conflicts between two simultaneous processes of the same application.
It's necessary to rename the procrun.exe for your particular application so in the "tasks list" you can see the appropriate executable name corresponding to your application name e.g. if it is necessary to "kill" the process.
Note that update_config.bat file contains some example options that are not needed by this class actually. These options should be removed in your application and replaced with any ones that are necessary for it. For instance proxy options are not necessary for this particular example.

пятница, 16 августа 2013 г.

Using [Far 2 + ConEmu]?
Here is the solution how to run new command in Far Manager 2 targeting the new ConEmu console.
Download and run this file to add macros for Far into the registry.
Now use ALT+SHIFT clicking ENTER on any item you wish to run in the new ConEmu console of the same ConEmu which runs Far. If command line is empty item under cursor on the file panel is running otherwise the command line typed in the text field under the panels is running.
The macro runs these commands adding the "-new_console" in the command line. The feature is working if ConEmu has been setup to intercept command line commands (you may check it in the settings, by default it is).

пятница, 8 марта 2013 г.

Needed a possibility to notify a thread about event occurred in anothre thread. Originally other attemps were made to organize the necessary approach inside that threads but then idea came up to use a separate object for this kind of synchronization and it finally came out as pretty intelegent light easy to read approach so good that I wanted to share it with you.

/*** Event Waiter object is to synchronize one or several threads with a thread-event originator</br>* Thread safe.</br>* Actors: event originator thread and one or more event waiter thread(s)</br>* Event Waiter thread(s) must call {@link #waitForEvent()} to wait for the Event to occur</br>* Event Originator thread must call {@link #eventOccurred()} to notify that the Event has been occurred</br>* If the Event has been occurred waiter thread(s) are not blocked on {@link #waitForEvent()} call</br>* If the Event has not been occurred yet waiter thread(s) are blocked on {@link #waitForEvent()} call until the Event has occurred</br>* * @author vtkachenko**/public class EventWaiter {private boolean eventOccurred = false;/*** Once the event has been occurred this method should be called to notify that*/public synchronized void eventOccurred() {eventOccurred = true;notifyAll();}/*** Method to wait for the event to occur* @throws InterruptedException*/public synchronized void waitForEvent() throws InterruptedException {if (!eventOccurred) {wait();}}}

понедельник, 16 июля 2012 г.

I've spent a lot of time on a problem when we need to assign just simple value to the tag body which has some attributes already assigned before. E.g. we have some variable varOut which contains the following structure:

But BPEL treats source anyway as a complex structure regardles which type is used to define it, let it be even xsd:string and as a result of this operation the whole complex destination (complexValue with its children which are its attributes for the given example) is replaced thus someAttr will be lost. To solve the problem we can use string function which converts object to simple value and have a copy made like this: