I have created a maven-plugin with some mojos, each has a very special purpose. But for the end user it would be nice to execute some of them at once (the order is crucial).
So how to execute other mojos from a mojos execute? The mojos being executed have some #Parameter fields. So i can't simple new MyMojo().execute.
My 2nd question is: Is there a way to share some #Parameters between Mojos or do i have to declare "#Parameter" in each Mojo that is using them?
My idea is to somehow deliver all shared Parameters via utility-class that is providing getters the parameters.
I think the answer to both question somehow lies in understanding the DI-mechanism behind maven-mojos?! I have some experience with Guice but no with Plexus. So could someone please give me some advises?
I don't know exactly what your second question means. Maybe they aren't really related. But I try to answer both starting with the first one.
Question 1: How to call a Goal from another Goal?
For this you can use the Apache Maven Invoker.
Add the Maven dependency to your plugin.
For example:
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-invoker</artifactId>
<version>2.2</version>
</dependency>
And then you can call another goal this way:
// parameters:
final Properties properties = new Properties();
properties.setProperty("example.param.one", exampleValueOne);
// prepare the execution:
final InvocationRequest invocationRequest = new DefaultInvocationRequest();
invocationRequest.setPomFile(new File(pom)); // pom could be an injected field annotated with '#Parameter(defaultValue = "${basedir}/pom.xml")' if you want to use the same pom for the second goal
invocationRequest.setGoals(Collections.singletonList("second-plugin:example-goal"));
invocationRequest.setProperties(properties);
// configure logging:
final Invoker invoker = new DefaultInvoker();
invoker.setOutputHandler(new LogOutputHandler(getLog())); // using getLog() here redirects all log output directly to the current console
// execute:
final InvocationResult invocationResult = invoker.execute(invocationRequest);
Question 2: How can I share parameters between mojos?
Did you mean:
How to share parameters between multiple goals inside of one plugin?(See "Answer for Question 2.1")
How to reuse parameters of your "meta mojo" for the executed "child mojos"?(See "Answer for Question 2.2")
Answer for question 2.1:
You can create a abstract parent class which contains the parameter fields.
Example:
abstract class AbstractMyPluginMojo extends Abstract Mojo {
#Parameter(required = true)
private String someParam;
protected String getSomeParam() {
return someParam;
}
}
#Mojo(name = "first-mojo")
public class MyFirstMojo extends AbstractMyPluginMojo {
public final void execute() {
getLog().info("someParam: " + getSomeParam());
}
}
#Mojo(name = "second-mojo")
public class MySecondMojo extends AbstractMyPluginMojo {
public final void execute() {
getLog().info("someParam: " + getSomeParam());
}
}
You can find this technique in almost avery larger maven plugin. For example look at the Apache Maven Plugin sources.
Answer for question 2.2:
You can ind the solution for this already in my answer to question 1. If you want to execute multiple goals inside your "meta mojo" you can just reuse the properties variable.
Related
I need to build a custom command in a Grails 4 application (https://docs.grails.org/4.0.11/guide/single.html#creatingCustomCommands), and I need to get an handle to some Grails Services and Domain classes which I will query as needed.
The custom command skeleton is quite simple:
import grails.dev.commands.*
import org.apache.maven.artifact.Artifact
class HelloWorldCommand implements GrailsApplicationCommand {
boolean handle() {
return true
}
}
While the documentation says that a custom command has access to the whole application context, I haven't found any examples on how to get an handle of that and start accessing the various application artifacts.
Any hints?
EDIT: to add context and clarify the goal of the custom command in order for further recommendation/best practices/etc.: the command reads data from a file in a custom format, persist the data, and writes reports in another custom format.
Will eventually be replaced by a recurrent job, once the data will be available on demand from a third party REST API.
See the project at github.com/jeffbrown/marco-vittorini-orgeas-artifacts-cli.
grails-app/services/marco/vittorini/orgeas/artifacts/cli/GreetingService.groovy
package marco.vittorini.orgeas.artifacts.cli
class GreetingService {
String greeting = 'Hello World'
}
grails-app/commands/marco/vittorini/orgeas/artifacts/cli/HelloCommand.groovy
package marco.vittorini.orgeas.artifacts.cli
import grails.dev.commands.*
class HelloCommand implements GrailsApplicationCommand {
GreetingService greetingService
boolean handle() {
println greetingService.greeting
return true
}
}
EDIT:
I have added a commit at github.com/jeffbrown/marco-vittorini-orgeas-artifacts-cli/commit/49a846e3902073f8ea0539fcde550f6d002b9d89 which demonstrates accessing a domain class, which was part of the question I overlooked when writing the initial answer.
I need to be able to create classes and use them within a Jenkins pipeline.
Let's say I have a very simple groovy class, declared in a groovy script, looking as this:
class MyClass {
#Override
public String toString() {
return "toto";
}
}
return MyClass();
This class is located in the folder: Project\Buildfiles\Jenkins\com\external
Then in my Jenkinsfile I would do:
node('mynode') {
toto = load 'Project\Buildfiles\Jenkins\com\external\MyClass.groovy'
echo toto.toString()
}
And this actually works
However this do pose a certain numbers of issues with my IDE which does not understand what is happening. Also, this prevents me to have several constructor in my custom class.
What I have been trying to do, and for which I need help, is the following. In a file named ExternalClasses.groovy:
class Toto{
#Override
public String toString() {
return "toto";
}
}
class Tata{
#Override
public String toString() {
return "tata";
}
}
return this;
In the JenkinsFile:
node('mynode') {
external= load 'Project\Buildfiles\Jenkins\com\external\ExternalClasses.groovy'
toto = new Toto();
tata = new Tata();
}
And this fails
I have tried several approaches, used packages names, used the Toto.new() syntax, but none worked.
Any ideas ?
Edit about Shared Libraries:
I actually have a Shared library, it is used by several teams and contains very specific data which should be own by the teams and not by the library.
We need to be able to put out of the library things which does not belong to it. The purpose of this work is to alleviate the said library of non generic code.
You could use the Shared Library Feature. Upload your scripts into a VCS like Github/Bitbucket and use Jenkins-Jobs to execute them. They are available for all projects/jobs.
I am new to grails and while working with Spring Security LDAP plugin it was identified that it accepts the ldap server password in plain text only. The task in hand is to pass an encrypted password which is decrypted before it is consumed by the plugin during its initialization phase.
I have already searched for all possible blogs and stackoverflow questions but could not find a way to extend the main plugin class to simply override the doWithSpring() method so that i can simply add the required decryption logic for the Ldap server password. Any help here will be appreciated.
I have already seen and tried jasypt plugin but it also does not work well if the password is stored in some external file and not application yml. So I am looking for a solution to extend the Spring security plugin main class, add the required behavior and register the custom class.
EDIT
Adding the snippet from Grails LDAP Security plugin, which I am trying to override. So If i am successfully able to update the value of securityConfig object before the plugin loads, the purpose is solved.
Some snippet from the plugin:
def conf = SpringSecurityUtils.securityConfig
...
...
contextSource(DefaultSpringSecurityContextSource, conf.ldap.context.server) { // 'ldap://localhost:389'
authenticationSource = ref('ldapAuthenticationSource')
authenticationStrategy = ref('authenticationStrategy')
userDn = conf.ldap.context.managerDn // 'cn=admin,dc=example,dc=com'
**password = conf.ldap.context.managerPassword // 'secret'**
contextFactory = contextFactoryClass
dirObjectFactory = dirObjectFactoryClass
baseEnvironmentProperties = conf.ldap.context.baseEnvironmentProperties // none
cacheEnvironmentProperties = conf.ldap.context.cacheEnvironmentProperties // true
anonymousReadOnly = conf.ldap.context.anonymousReadOnly // false
referral = conf.ldap.context.referral // null
}
ldapAuthenticationSource(SimpleAuthenticationSource) {
principal = conf.ldap.context.managerDn // 'cn=admin,dc=example,dc=com'
**credentials = conf.ldap.context.managerPassword // 'secret'**
}
You don't need to override the doWithSpring() method in the existing plugin. You can provide your own plugin which loads after the one you want to affect and have your doWithSpring() add whatever you want to the context. If you add beans with the same name as the ones added by the other plugin, yours will replace the ones provided by the other plugin as long as you configure your plugin to load after the other one. Similarly, you could do the same think in resources.groovy of the app if you don't want to write a plugin for this.
You have other options too. You could write a bean post processor or bean definition post processor that affects the beans created by the other plugin. Depending on the particulars, that might be a better idea.
EDIT:
After seeing your comment below I created a simple example that shows how you might use a definition post processor. See the project at https://github.com/jeffbrown/postprocessordemo.
The interesting bits:
https://github.com/jeffbrown/postprocessordemo/blob/master/src/main/groovy/demo/SomeBean.groovy
package demo
class SomeBean {
String someValue
}
https://github.com/jeffbrown/postprocessordemo/blob/master/src/main/groovy/demo/SomePostProcessor.groovy
package demo
import org.springframework.beans.BeansException
import org.springframework.beans.MutablePropertyValues
import org.springframework.beans.PropertyValue
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
import org.springframework.beans.factory.support.BeanDefinitionRegistry
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
class SomePostProcessor implements BeanDefinitionRegistryPostProcessor{
#Override
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition definition = registry.getBeanDefinition('someBean')
MutablePropertyValues values = definition.getPropertyValues()
PropertyValue value = values.getPropertyValue('someValue')
def originalValue = value.getValue()
// this is where you could do your decrypting...
values.addPropertyValue('someValue', "MODIFIED: ${originalValue}".toString())
}
#Override
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
https://github.com/jeffbrown/postprocessordemo/blob/master/grails-app/conf/spring/resources.groovy
beans = {
someBean(demo.SomeBean) {
someValue = 'Some Value'
}
somePostProcessor demo.SomePostProcessor
}
https://github.com/jeffbrown/postprocessordemo/blob/master/grails-app/init/postprocessordemo/BootStrap.groovy
package postprocessordemo
import demo.SomeBean
class BootStrap {
SomeBean someBean
def init = { servletContext ->
log.info "The Value: ${someBean.someValue}"
}
def destroy = {
}
}
At application startup you will see log output that looks something like this...
2017-10-23 19:04:54.356 INFO --- [ main] postprocessordemo.BootStrap : The Value: MODIFIED: Some Value
The "MODIFIED" there is evidence that the bean definition post processor modified the property value in the bean. In my example I am simply prepending some text to the string. In your implementation you could decrypt a password or do whatever you want to do there.
I hope that helps.
After trying Jasypt plugin and BeanPostProcessor solutions unsuccessfully for my use case, I found below solution to work perfectly.
To describe again the problem statement here,
a) we had to keep the passwords in an encrypted format inside properties files
b) and given we were packaging as a war file so the properties must not be kept inside the war to allow automated deployment scripts update the encrypted passwords depending on the environment
Jasypt plugin was a perfect solution for the use case a), but it was not able to cover the b) scenario
Moreover, the Grails LDAP Security plugin was getting loaded quite early hence Bean Post processors were also not helping out here.
Solution:
Created a new class by implementing the interface SpringApplicationRunListener. Extended its methods and parsed the properties file using YamlPropertySourceLoader
Sample code:
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
PropertySource<?> applicationYamlPropertySource = loader.load(
"application.yml", new ClassPathResource("application.yml"),"default");
return applicationYamlPropertySource;
Once the properties were loaded inside the MapPropertySource object, parsed them for the encrypted values and applied the decryption logic.
This whole implementation was executed before any plugins were initialized during Grails bootup process solving the purpose.
Hope it will help others.
I'm building REST API on the top of Spring Data Rest. Initially all repositories where extending JpaRepository. Lately decision has been made to take a more flexible approach and use QueryDslPredicateExecutor<T> along with QuerydslBinderCustomizer<Q>.
Pretty much all findAll methods exposed in repositories should address two scenarios
principal has a role ROLE_ADMIN then no filtering should be applied a part from Pageable,Sort
principal does not have a role ROLE_ADMIN I would return only those entities which belong to the current user
Getting that done was as simple as annotating findAll method as below.
#Query("select e from Entity e where e.field = ?#{principal} or 1=?#{hasRole('ROLE_ADMIN') ? 1 : 0}")
Page<Entity> findAll(Pageable pageable);
Now I want our findAll to be something similar to below
Page<Entity> findAll(Predicate predicate, Pageable pageable)
Predicate is being build from request parameters(courtesy of #QuerydslPredicate) and is being passed in to RepositoryEntityController which is all being managed by spring-data-rest which is great.
#ResponseBody
#RequestMapping(value = BASE_MAPPING, method = RequestMethod.GET)
public Resources<?> getCollectionResource(#QuerydslPredicate RootResourceInformation resourceInformation,
DefaultedPageable pageable, Sort sort, PersistentEntityResourceAssembler assembler)
throws ResourceNotFoundException, HttpRequestMethodNotSupportedException {
I want to tweak that predicate(2 scenarios as above that I want to address).
It would be something simialr to below.
BooleanBuilder builder = new BooleanBuilder(predicateBuildFromHttpRequest);
builder.and(predicateAddressingOurRequirements);
builder.getValue();
#PostFilter won't be an option as return type for all repos is Page<Entity>.
Use case that I want to address seems to be quite common to me. Having said that I had a look at spring-data and spring-data-rest documentation and could not find anything related to my question.
Question is : Am I missing something obvious here and there is a quick win for it? or I would need to implement custom solution myself? Any comments very much appreciated!
The Querydsl predicates are constructed by QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver which is sadly package private and can't be directly extended.
However, you can make a copy of that, add your security predicate logic and then drop in your implementation instead of the former resolver.
public class MyQueryDslRootResourceArgumentResolver extends RootResourceInformationHandlerMethodArgumentResolver {
// the most of the code is ommitted, the content is identical with
// QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver,
// the important part is postProcessMethod where you can modify the predicate
#Override
#SuppressWarnings({"unchecked"})
protected RepositoryInvoker postProcess(MethodParameter parameter, RepositoryInvoker invoker,
Class<?> domainType, Map<String, String[]> parameters) {
Object repository = repositories.getRepositoryFor(domainType);
if (!QueryDslPredicateExecutor.class.isInstance(repository)
|| !parameter.hasParameterAnnotation(QuerydslPredicate.class)) {
return invoker;
}
ClassTypeInformation<?> type = ClassTypeInformation.from(domainType);
QuerydslBindings bindings = factory.createBindingsFor(null, type);
// modify your predicate here
Predicate predicate = predicateBuilder.getPredicate(type, toMultiValueMap(parameters), bindings);
return new QuerydslRepositoryInvokerAdapter(invoker, (QueryDslPredicateExecutor<Object>) repository, predicate);
}
}
Then add you own configuration class with the custom resolver implementation.
public class CustomRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
#Autowired
ApplicationContext applicationContext;
#Override
public RootResourceInformationHandlerMethodArgumentResolver repoRequestArgumentResolver() {
QuerydslBindingsFactory factory = applicationContext.getBean(QuerydslBindingsFactory.class);
QuerydslPredicateBuilder predicateBuilder = new QuerydslPredicateBuilder(defaultConversionService(),
factory.getEntityPathResolver());
return new MyQueryDslRootResourceArgumentResolver(repositories(),
repositoryInvokerFactory(defaultConversionService()), resourceMetadataHandlerMethodArgumentResolver(),
predicateBuilder, factory);
}
}
Here is an example project that modifies the Predicate (that is produced by the parameters from url) before passing it to the repository.
The demonstration of what David Siro explained above
https://github.com/yeldarxman/QueryDslPredicateModifier
I have two questions today. This is detailed because too many other replies rely on assumptions and have not been detailed enough. I hope that this is detailed and will be able to help lots of developers.
1st. The code below points to the real question I have. How do you call a Service outside of the controller since the $this->get() method is inside of the controller only? This is not in any of the documentation or on KNP University's tutorial on Services.
2nd. From what I have read, according to some, not all, if you call to a Repository, from anywhere, it should automatically instantiate the Entity Repository. I don't think this is so. Tell me if I am right or wrong.
See the following below....
My Default Controller, it's straightforward call a class and let it do some work. As an example, I called it with a Service and a conventional OO method:
<?php
// src/AppBundle/Controller/DefaultController.php
// Here is where I am starting. There is a service
// and there is a conventional OO call.
// Both should invoke the same thing.
namespace AppBundle\Controller;
use AppBundle\Service;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
// Step 1.... Do a little of this.
// Step 2.... Do some of that.
// Step 3.... Call another class to do some logic and it will
// eventually call a query...
// Invoking my service
$obj_via_service = $this->get('app.services.process_question');
$result1 = $obj_via_service->submitQuestion();
// Invoking via Namespace and Call
$obj_via_new = new Service\ProcessQuestion();
$result2 = $obj_via_new->submitQuestion();
dump($result1);
dump($result2);
die();
}
}
My Service.yml File.
# src/app/config/services.yml
parameters:
services:
app.services.process_question:
class: AppBundle\Service\ProcessQuestion
app.rep.geo_state:
class: AppBundle\Entity\GeoStateRepository
arguments: ['#doctrine.orm.entity_manager']
This is my class that is doing the work for me. I want to be able to call the second service ^^above^^ but I can't because I can't use $this->get() outside of the controller.
<?php
// src/AppBundle/Service/ProcessQuestion.php
namespace AppBundle\Service;
class ProcessQuestion
{
public function submitQuestion()
{
// Step 1.... Do this.
// Step 2.... Do that.
// Step 3.... Query for some data...
// Invoke my repository class via a Service Call....
// but I cannot do that because 'get' is a part of the
// controller...
$obj_via_service = $this->get('app.rep.geo_state');
**^^ ^^**
**^^ This is what won't work ^^**
$results = $obj_via_service->selectStates();
return $results;
}
}
My Repository Class... Keep in mind I cannot reach this class yet, but I am throwing it in here so that other new Symfony 3 developers can see this.
<?php
// src/AppBundle/Repository/GeoState.php
// My Repository Class where I want to do some queries...
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
class GeoStateRepository extends EntityRepository
{
/**
* #Mapping\Column(type="string")
*/
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function selectStates()
{
$sql = "SELECT * FROM geo_state";
return $this->getEntityManager()->createQuery($sql)->getResult();
}
}
Why is this so hard to find an example? Also, I have followed a bunch of the Symfony 2.x documentation and the nuances are hard to port into Symfony 3 sometimes.
I think Fabian re purposed too much of the docs for 2.x to go into 3.x and there is not any good examples on coding that is between the New Developer level and the Hard Core Developer level. If you are at Sensio and reading this, please keep in mind that there is a middle ground we need to cover and most of the screencasts that out there and much of the better documentation is not in English.
You should really read more about Dependency Injection.
Symfony is very good at this .
Regarding your question about using app.rep.geo_state service in the app.services.process_question service .
In Symfony/ DI terminology it's can be termed as injecting a service into another service .
The documentation on how to do this is very good.
this is how it can be done.
services:
app.services.process_question:
class: AppBundle\Service\ProcessQuestion
arguments: ['#app.rep.geo_state']
app.rep.geo_state:
class: AppBundle\Entity\GeoStateRepository
arguments: ['#doctrine.orm.entity_manager']
And in the class
<?php
// src/AppBundle/Service/ProcessQuestion.php
namespace AppBundle\Service;
use AppBundle\Entity\GeoStateRepository;
class ProcessQuestion
{
private $geoRepository;
public function __construct(GeoStateRepository $geoRepository)
{
$this->geoRepository = $geoRepository;
}
public function submitQuestion()
{
//now you can call $this->geoRepository
}
}
Also note that $this->get() is only a shortcut function provided by the Symfony base Controller class to access the container.
To know more about DI, you can read Fabian's excellent articles about this in his blog .