How to get command line arguments of an Eclipse 4 application from code - rcp

I need to somehow get command line arguments of a running Eclipse 4 application. I'm working on a small application based on the Eclipse 4 RCP, but I thing, this problem is more common. I'm unable to find out, how to get from code of a product respectively of a plug-in the command line argumnets, the application have been executed with.
I need to use a custom command line parameter to pass on information to my code. Do anybody know a hint?

Since E4 is using Equinox as runtime you can use the Platform class to get the application arguments.
Platform.getApplicationArgs()
See Javadoc:
http://help.eclipse.org/kepler/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Findex.html

I've got it. It is not so intuitive, but it works for me. There is an instance implementing the IApplicationContext interface. (The interface depends on the org.eclipse.equinox.app.) The instance is reachable by the injection mechanism. The method getArguments() returns a map. But it does not return a map of some command line parameters and their values. It returns some map, where it is under the key "application.args" stored an array. Exampli gratia:
#PostConstruct
public void createControls(Composite parent, HtmlEditorService editorService, IApplicationContext iac) {
System.out.println(iac.getArguments().get("application.args").getClass().getCanonicalName());
...
}
Then it prints out java.lang.String[]. However the array contains just my custom arguments instead all arguments. Fortunately it does not matter for me. I need to get my custom arguments only.
Additional hint for a plug-in activator
public class Aktivator implements BundleActivator {
#Override
public void start(BundleContext context) throws Exception {
ServiceReference<?> ser = context.getServiceReference(IApplicationContext.class);
IApplicationContext iac = (IApplicationContext)context.getService(ser);
System.out.println(iac.getArguments().get("application.args").getClass().getCanonicalName());
}
#Override
public void stop(BundleContext context) throws Exception {
}
}

Related

Remove a Spring ConversionService across the entire application

I am running with Spring 3.2.18 (I know, it's old) with Spring MVC. My issue is that there is at least one default request parameter conversion (String -> List) that fails when there is actually only one item in the array, but it has commas. This is because the default conversion built into Spring will see it as a comma-separated list.
I am NOT using Spring Boot, so please avoid answers that specifically reference solutions using it.
I tried adding a #PostConstruct method to a #Confuguration class as follows:
#Configuration
public class MyConfig {
#Autowired
private ConfigurableEnvironment env;
#PostConstruct
public void removeConverters() {
ConfigurableConversionService conversionService = env.getConversionService();
conversionService.removeConvertible(String.class, Collection.class);
}
}
This runs on startup but the broken conversion still occurs. I put a breakpoint in this method, and it is called only once on startup. I verified that it removed a converter that matched the signature of String -> Collection.
The following works, but when I put a breakpoint in the #InitBinder method it acts like it gets called once for every request parameter on every request.
#ControllerAdvice
public class MyController {
#InitBinder
public void initBinder(WebDataBinder binder) {
GenericConversionService conversionService = (GenericConversionService) binder.getConversionService();
conversionService.removeConvertible(String.class, Collection.class);
}
}
As I said the second one works, but it makes no sense that the offending converter has to be removed for every request made to that method - let alone for every request parameter that method takes.
Can someone please tell me why this only works when the removal is incredibly redundant? Better yet, please tell me how I'm doing the one-time, application-scope removal incorrectly.

Custom TeamCity plugin with a Build Feature that executes a long running process

I am developing a custom TeamCity plugin that integrates with an enterprise deployment platform. It should deploy the binaries at the end of the build to some deployment platform by executing a command line command. Currently there is a class that extends the BuildFeature class on the server side to setup the details of artifacts to be deployed. On the agent side there is a class that extends AgentLifeCycleAdapter class, which overrides the beforeBuildFinish() method and executes a long running command line process. I am using SimpleCommandLineProcessRunner class to execute the external command line process:
final ExecResult result = SimpleCommandLineProcessRunner.runCommand(commandLine,
null,
new SimpleCommandLineProcessRunner.RunCommandEventsAdapter());
The process is being stopped after two minutes, which looks like some timeout:
[18:13:50]Running as atom_builder
[18:13:50]Executing C:\TeamCity\buildAgent\work\db4107aa7e390a67\adeploy\adeploy.exe
artifactVersion push
C:\TeamCity\buildAgent\work\db4107aa7e390a67\agent\atom-agent-artifact-version.xml
[18:13:50]Running at C:\TeamCity\buildAgent\work\db4107aa7e390a67\agent
[18:15:22]2018-11-07 18:13:51 [Information]
["ArtifactPushService:PushArtifactAsync"] Calling method with parameters '"adeploy.exe" [18:15:22]Exit code: -1
What is the proper way to execute long running processes as part of the build when the build configuration has a custom Build Feature?
I found out the answer, so I will post it here, in case somebody else encounter the same problem.
Since we are talking about custom plugin, it's completely in the code of the agent -side of the plugin that executes the external process. As stated in the question, the external process is executed using SimpleCommandLineProcessRunner class and it passes an instance of RunCommandEventsAdapter class. The last one returns null in getOutputIdleSecondsTimeout() method. It means that SimpleCommandLineProcessRunner will use default timeout of 90 seconds unless it's defined in teamcity.execution.timeout parameter.
So the solution is to define a LongRunningProcessRunCallback class that implements ProcessRunCallback interface. Put attention that getOutputIdleSecondsTimeout() returns a pretty long timeout.
public class LongRunningProcessRunCallback implements SimpleCommandLineProcessRunner.ProcessRunCallback {
private static final int DEFAULT_TIMEOUT_SECONDS = 60 * 60 * 24;
#Nullable
#Override
public Integer getMaxAcceptedOutputSize() {
return null;
}
#Override
public void onProcessStarted(#NotNull Process process) {
}
#Override
public void onProcessFinished(#NotNull Process process) {
}
#Nullable
#Override
public Integer getOutputIdleSecondsTimeout() {
return TeamCityProperties.getInteger("teamcity.execution.timeout", DEFAULT_TIMEOUT_SECONDS);
}
}
And then pass it to SimpleCommandLieProcessRunner:
final ExecResult result = SimpleCommandLineProcessRunner.runCommand(commandLine,
null,
new LongRunningProcessRunCallback());

Spring validation keeps validating the wrong argument

I have a controller with a web method that looks like this:
public Response registerDevice(
#Valid final Device device,
#RequestBody final Tokens tokens
) {...}
And a validator that looks like this:
public class DeviceValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return Device.class.isAssignableFrom(clazz);
}
#Override
public void validate(Object target, Errors errors) {
// Do magic
}
}
}
I'm trying to get Spring to validate the Device argument which is being generated by an interceptor. But every time I try, it validates the tokens argument instead.
I've tried using #InitBinder to specify the validator, #Validated instead of #Validand registering MethodValidationPostProcessor classes. So far with no luck.
Either the validator is not called at all, or tokens argument is validated when I was the Device argument validated.
I'm using Spring 4.1.6 and Hibernate validator 5.1.3.
Can anyone offer any clues as to what I'm doing wrong? I've searched the web all afternoon trying to sort this out. Can't believe that the validation area of spring is still as messed up as it was 5 years ago :-(
Ok. Have now solved it after two days of messing about with all sorts of variations. If there is one thing Spring's validation lets you do - it's come up with an incredible array of things that don't work! But back to my solution.
Basically what I needed was a way to manually create request mapping arguments, validate them and then ensure that no matter whether it was a success or failure, that the caller always received a custom JSON response. Doing this proved a lot harder than I thought because despite the number of blog posts and stackoverflow answers, I never found a complete solution. So I've endeavoured to outline each piece of the puzzle needed to achieve what I wanted.
Note: in the following code samples, I've generalised the names of things to help clarify whats custom and whats not.
Configuration
Although several blog posts I read talked about various classes such as the MethodValidationPostProcessor, in the end I found I didn't need anything setup beyond the #EnableWebMvc annotation. The default resolvers etc proved to be what I needed.
Request Mapping
My final request mapping signatures looked like this:
#RequestMapping(...)
public MyMsgObject handleRequest (
#Valid final MyHeaderObj myHeaderObj,
#RequestBody final MyRequestPayload myRequestPayload
) {...}
You will note here that unlike just about every blog post and sample I found, I have two objects being passed to the method. The first is an object that I want to dynamically generate from the headers. The second is a deserialised object from the JSON payload. Other objects could just as easily be included such as path arguments etc. Try something like this without the code below and you will get a wide variety of weird and wonderful errors.
The tricky part that caused me all the pain was that I wanted to validate the myHeaderObj instance, and NOT validate the myRequestPayload instance. This caused quite a headache to resolve.
Also note the MyMsgObject result object. Here I want to return an object that will be serialised out to JSON. Including when exceptions occur as this class contains error fields that need to be populated in addition to the HttpStatus code.
Controller Advice
Next I created an ControllerAdvice class which contained the binding for validation and a general error trap.
#ControllerAdvice
public class MyControllerAdvice {
#Autowired
private MyCustomValidator customValidator;
#InitBinder
protected void initBinder(WebDataBinder binder) {
if (binder.getTarget() == null) {
// Plain arguments have a null target.
return;
}
if (MyHeaderObj.class.isAssignableFrom(binder.getTarget().getClass())) {
binder.addValidators(this.customValidator);
}
}
#ExceptionHandler(Exception.class)
#ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
#ResponseBody
public MyMsgObject handleException(Exception e) {
MyMsgObject myMsgObject = new MyMsgObject();
myMsgObject.setStatus(MyStatus.Failure);
myMsgObject.setMessage(e.getMessage());
return myMsgObject;
}
}
Two things going on here. The first is registering the validator. Note that we have to check the type of the argument. This is because #InitBinder is called for each argument to the #RequestMapping and we only want the validator on the MyHeaderObj argument. If we don't do this, exceptions will be thrown when Spring attempts to apply the validator to arguments it's not valid for.
The second thing is the exception handler. We have to use #ResponseBody to ensure that Spring treats the returned object as something to be serialised out. Otherwise we will just get the standard HTML exception report.
Validator
Here we use a pretty standard validator implementation.
#Component
public class MyCustomValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return MyHeaderObj.class.isAssignableFrom(clazz);
}
#Override
public void validate(Object target, Errors errors) {
...
errors.rejectValue("fieldName", "ErrorCode", "Invalid ...");
}
}
One thing that I still don't really get with this is the supports(Class<?> clazz) method. I would have thought that Spring uses this method to test arguments to decide if this validator should apply. But it doesn't. Hence all the code in the #InitBinder to decide when to apply this validator.
The Argument Handler
This is the biggest piece of code. Here we need to generate the MyHeaderObj object to be passed to the #RequestMapping. Spring will auto detect this class.
public class MyHeaderObjArgumentHandler implements HandlerMethodArgumentResolver {
#Override
public boolean supportsParameter(MethodParameter parameter) {
return MyHeaderObj.class.isAssignableFrom(parameter.getParameterType());
}
#Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
// Code to generate the instance of MyHeaderObj!
MyHeaderObj myHeaderObj = ...;
// Call validators if the argument has validation annotations.
WebDataBinder binder = binderFactory.createBinder(webRequest, myHeaderObj, parameter.getParameterName());
this.validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors()) {
throw new MyCustomException(myHeaderObj);
}
return myHeaderObj;
}
protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) {
Annotation[] annotations = methodParam.getParameterAnnotations();
for (Annotation ann : annotations) {
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] { hints });
binder.validate(validationHints);
break;
}
}
}
}
The main job of this class is to use whatever means it requires to build the argument (myHeaderObj). Once built it then proceeds to call the Spring validators to check this instance. If there is a problem (as detected by checking the returned errors), it then throws an exception that the #ExceptionHandler's can detect and process.
Note the validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) method. This is code I found in a number of Spring's classes. It's job is to detect if any argument has a #Validated or #Valid annotation and if so, call the associated validators. By default, Spring does not do this for custom argument handlers like this one, so it's up to us to add this functionality. Seriously Spring ???? No AbstractSomething ????
The last piece, explicit Exception catches
Lastly I also needed to catch more explicit exceptions. For example the MyCustomException thrown above. So here I created a second #ControllerAdvise.
#ControllerAdvice
#Order(Ordered.HIGHEST_PRECEDENCE) // Make sure we get the highest priority.
public class MyCustomExceptionHandler {
#ExceptionHandler
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
#ResponseBody
public Response handleException(MyCustomException e) {
MyMsgObject myMsgObject = new MyMsgObject();
myMsgObject.setStatus(MyStatus.Failure);
myMsgObject.setMessage(e.getMessage());
return myMsgObject;
}
}
Although superficially the similar to the general exception handler. There is one different. We need to specify the #Order(Ordered.HIGHEST_PRECEDENCE) annotation. Without this, Spring will just execute the first exception handler that matches the thrown exception. Regardless of whether there is a better matching handler or not. So we use this annotation to ensure that this exception handler is given precedence over the general one.
Summary
This solution works well for me. I'm not sure that I've got the best solution and there may be Spring classes which I've not found which can help. I hope this helps anyone with the same or similar problems.

Spring batch how to use ItemReadListener

I use spring batch for processing a file. The configuration of all components is made programatically.
I have a job that contains several TaskletSteps:
#Bean
#Named(SEEC_JOB)
public Job seecJob() {
return jobBuilderFactory.get(SEEC_JOB).start(seecMoveToWorkingStep()).next(seecLoadFileStep())
.on(ExitStatus.COMPLETED.getExitCode()).to(seecFlowMoveToArchiveOk()).from(seecLoadFileStep())
.on(ExitStatus.FAILED.getExitCode()).to(seecFlowMoveToArchiveKo()).end().build();
}
My question focus on seecLoadFileStep(), the detail bellow:
#Bean
public TaskletStep seecLoadFileStep() {
TaskletStep build = stepBuilderFactory.get(SEEC_LOAD_FILE_STEP)
.<SeecMove, SeecMove>chunk(cormoranProperties.seec.batchSize.get()).reader(seecItemReader())
.writer(seecItemWriter()).build();
return build;
}
I would like to throw a specific exception if a reading error hapens (by reading error I mean: the file is corrupted for example or it is wrong, absent xml tag...).
I have been reading spring batch doc and I think ItemReadListener is my guy:
public interface ItemReadListener<T> extends StepListener {
void beforeRead();
void afterRead(T item);
void onReadError(Exception ex);
}
but, I don't know how to use it! I have tried doing my seecItemReader() implements this interface but onReadError method is never called.
I don't know how to declare/register in the taskletStep the ItemReadListener.
Here a bit of spring doc:
Any class that implements one of the extensions of StepListener (but
not that interface itself since it is empty) can be applied to a step
via the listeners element. The listeners element is valid inside a
step, tasklet or chunk declaration. It is recommended that you declare
the listeners at the level which its function applies, or if it is
multi-featured (e.g. StepExecutionListener and ItemReadListener) then
declare it at the most granular level that it applies (chunk in the
example given).
An ItemReader, ItemWriter or ItemProcessor that itself implements one
of the StepListener interfaces will be registered automatically with
the Step if using the namespace element, or one of the the
*StepFactoryBean factories. This only applies to components directly injected into the Step: if the listener is nested inside another
component, it needs to be explicitly registered (as described above).
Could you please help me?
Thanks in advance!
As I guessed it was easier than I thougth, for registering programatically the ItemReadListener is via listener method in the tasklet configuration:
#Bean
public TaskletStep seecLoadFileStep() {
TaskletStep build = stepBuilderFactory.get(SEEC_LOAD_FILE_STEP)
.<SeecMove, SeecMove>chunk(cormoranProperties.seec.batchSize.get()).reader(seecItemReader()).listener(seecItemReaderListener())
.writer(seecItemWriter()).build();
return build;
}
And now the onError method is called when an Exception happens.

Why cannot Reducer.class used as a real reducer in Hadoop MapReduce?

I noticed that Mapper.class can be used as a real mapper in a phase, together with a user-defined reducer. For example,
Phase 1:
Mapper.class -> WordCountReduce.class
This will work.
However, Reducer.class cannot be used the same way. Namely something like
Phase 2:
WordReadMap.class -> Reducer.class
will not work.
Why is that?
I don't see why it wouldn't as long as the outputs are of the same class as the inputs. The default in the new API just writes out whatever you pass into it, it's implemented as
#SuppressWarnings("unchecked")
protected void reduce(KEYIN key, Iterable<VALUEIN> values, Context context
) throws IOException, InterruptedException {
for(VALUEIN value: values) {
context.write((KEYOUT) key, (VALUEOUT) value);
}
}
For the old API, it's an interface, and you can't directly instantiate an interface. If you're using that, then that's the reason it fails. Then again, the Mapper is an interface as well, and you shouldn't be able to instantiate it...

Resources