Tapestry: Inject at runtime - java

again a small problem by understanding "how tapestry works".
I've got a Tapestry component (in this case a value encoder):
public class EditionEncoder implements ValueEncoder<Edition>, ValueEncoderFactory<Edition> {
#Inject
private IEditionManager editionDao;
public EditionEncoder(IEditionManager editionDao) {
this.editionManager = editionDao;
}
#Override
public String toClient(Edition value) {
if(value == null) {
return "";
}
return value.getName();
}
#Override
public Edition toValue(String clientValue) {
if(clientValue.equals("")) {
return null;
}
return editionManager.getEditionByName(clientValue);
}
#Override
public ValueEncoder<Edition> create(Class<Edition> type) {
return this;
}
}
Injecting the the Manager is not working, because the Encoder is created within a page like that:
public void create() {
editionEncoder = new EditionEncoder();
}
casued by this, i'm forced to use this ugly solution:
#Inject
private IEditionManager editionmanager;
editionEncoder = new EditionEncoder(editionManager);
Is there a better way to inject components during runtime or is there a better solution in general for it?
Thanks for your help in advance,

As soon as you use "new" then tapestry-ioc is not involved in object creation and can't inject. You should inject everything and never use "new" for singleton services. This is true for all ioc containers, not just tapestry-ioc.
Also if you put #Inject on a field then you don't also need a constructor to set it. Do one or the other, never both.
You should do something like this:
public class MyAppModule {
public void bind(ServiceBinder binder) {
binder.bind(EditionEncoder.class);
}
}
Then in your page/component/service
#Inject EditionEncoder editionEncoder;
If you wanted to put your own instantiated objects in there you can do
public class MyServiceModule {
public void bind(ServiceBinder binder) {
binder.bind(Service1.class, Service1Impl.class);
binder.bind(Service2.class, Service2Impl.class);
}
public SomeService buildSomeService(Service1 service1, Service2 service2, #AutoBuild Service3Impl service3) {
Date someDate = new Date();
return new SomeServiceImpl(service1, service2, service3, someDate);
}
}

Related

Spring custom Scope with timed refresh of beans

I am working within an environment that changes credentials every several minutes. In order for beans that implement clients who depend on these credentials to work, the beans need to be refreshed. I decided that a good approach for that would be implementing a custom scope for it.
After looking around a bit on the documentation I found that the main method for a scope to be implemented is the get method:
public class CyberArkScope implements Scope {
private Map<String, Pair<LocalDateTime, Object>> scopedObjects = new ConcurrentHashMap<>();
private Map<String, Runnable> destructionCallbacks = new ConcurrentHashMap<>();
private Integer scopeRefresh;
public CyberArkScope(Integer scopeRefresh) {
this.scopeRefresh = scopeRefresh;
}
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name) || scopedObjects.get(name).getKey()
.isBefore(LocalDateTime.now().minusMinutes(scopeRefresh))) {
scopedObjects.put(name, Pair.of(LocalDateTime.now(), objectFactory.getObject()));
}
return scopedObjects.get(name).getValue();
}
#Override
public Object remove(String name) {
destructionCallbacks.remove(name);
return scopedObjects.remove(name);
}
#Override
public void registerDestructionCallback(String name, Runnable runnable) {
destructionCallbacks.put(name, runnable);
}
#Override
public Object resolveContextualObject(String name) {
return null;
}
#Override
public String getConversationId() {
return "CyberArk";
}
}
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk")
public String dateString(){
return LocalDateTime.now().toString();
}
}
#RestController
public class HelloWorld {
#Autowired
private String dateString;
#RequestMapping("/")
public String index() {
return dateString;
}
}
When I debug this implemetation with a simple String scope autowired in a controller I see that the get method is only called once in the startup and never again. So this means that the bean is never again refreshed. Is there something wrong in this behaviour or is that how the get method is supposed to work?
It seems you need to also define the proxyMode which injects an AOP proxy instead of a static reference to a string. Note that the bean class cant be final. This solved it:
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk", proxyMode=ScopedProxyMode.TARGET_CLASS)
public NonFinalString dateString(){
return new NonFinalString(LocalDateTime.now());
}
}

Wire collection of objects dynamically in Guice

Guice newbie here, with a complicated scenario.
My company has a large number of constants of a given type (let's call them Thingy) that belong to different teams and are maintained in different parts of our application. However, we need to have a central registry that knows about all of them (let's call this the ThingyService). I am writing a base module that teams can either extend or install, with the purpose of allowing a team to register their Thingys, and giving them access to the ThingyService. This module takes as parameter a list of classes from which I can extract the Thingy constants, this part is working fine.
What I don't understand is how I can a) make each module know about each other module's list of Thingys and b) how I can create my ThingyService as a singleton that contains all of my Thingys. I have experimented with shared static state and with ThreadLocals, but I keep either breaking tests or breaking my main (play) application. In my naive understanding of Guice, I think I need a MultiBinder for the Thingys, but I don't see how I can share that between modules. Here's what I'd like to do:
class ThingyModule extends AbstractModule{
final Set<Class<?>> myThingyClasses; // this is populated in the constructor
private Set<Thingy> extractThingiesFromThingyClasses(){
// I have this working
}
#Provides #Singleton ThingyService thingyService(
Set<Thingy> thingys // all thingys, from all such modules
){
return new ThingyService(thingys);
}
protected void configure(){
extractThingiesFromThingyClasses().forEach(thingy->
// bind thingy to a global MultiBinder?
);
}
}
How can I make my ThingyService unique and global, with all the Thingys from the entire application? Note: I don't necessarily need my Thingys to be managed by Guice, the only place I need them is in ThingyService. Also, this is a play / scala application if that makes a difference, but my ThingyModule code lives in a library written in Java.
It turns out I omitted one important detail, Thingy has a type parameter, it's actually Thingy<T>, and that's the reason it didn't work before. By cheating and registering Thingy as raw type, and then also injecting it as raw type, I got it to work.
Here is a complete working example using JUnit 5 and AssertJ:
class ThingyModuleTest {
static class Thingy<T>{
private final T value;
Thingy(final T value) {this.value = value;}
#Override public boolean equals(final Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
final Thingy<?> thingy = (Thingy<?>) o; return Objects.equals(value, thingy.value); }
#Override public int hashCode() { return Objects.hash(value); }
}
#Singleton
static class ThingyService{
final Set<Thingy<?>> thingies;
#SuppressWarnings({"unchecked", "rawtypes"}) #Inject
ThingyService(Set<Thingy> thingies) {
this.thingies = ImmutableSet.copyOf((Set)thingies);
}
public Set<Thingy<?>> getThingies() { return thingies; }
}
abstract static class ThingyModule extends AbstractModule {
private final Set<Class<?>> classesToScan;
public ThingyModule(Class<?>... classes) {
this.classesToScan = ImmutableSet.copyOf(classes);
}
private Set<Thingy<?>> scanForThingies(){
return classesToScan.stream()
.flatMap(c-> Arrays.stream(c.getDeclaredFields()))
.filter(f->f.getType().isAssignableFrom(Thingy.class))
.filter(f-> Modifier.isStatic(f.getModifiers())&&Modifier.isFinal(f.getModifiers()))
.map(this::readThingy)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toSet());
}
#SuppressWarnings("unchecked")
private Optional<Thingy<?>> readThingy(final Field field) {
try{
field.setAccessible(true);
return Optional.ofNullable(field.get(null))
.filter(Thingy.class::isInstance)
.map(Thingy.class::cast);
} catch (IllegalAccessException e) { return Optional.empty(); }
}
#Override protected void configure() {
bind(ThingyService.class);
#SuppressWarnings("rawtypes") Multibinder<Thingy> multibinder = Multibinder.newSetBinder(binder(), Thingy.class);
scanForThingies().forEach(thingy -> multibinder.addBinding().toInstance(thingy));
}
}
static class ThingyModule1 extends ThingyModule {
public ThingyModule1() { super(Thingies1.class); }
static class Thingies1{
static final Thingy<Boolean> BooleanThingy = new Thingy<>(true);
static final Thingy<Integer> IntThingy = new Thingy<>(123);
}
}
static class ThingyModule2 extends ThingyModule {
public ThingyModule2() { super(Thingies2.class); }
static class Thingies2{
static final Thingy<String> StringThingy = new Thingy<>("hello");
static final Thingy<Long> LongThingy = new Thingy<>(123L);
}
}
#Test void validateThingyService() {
ThingyService thingyService = Guice.createInjector(new ThingyModule1(), new ThingyModule2())
.getProvider(ThingyService.class)
.get();
assertThat(thingyService).isNotNull()
.extracting(ts -> ImmutableList.copyOf(ts.getThingies()))
.asList()
.containsExactlyInAnyOrder(BooleanThingy, IntThingy, StringThingy, LongThingy);
}
}
I will mark this answer as accepted until somebody else provides a more idiomatic one.

Object inheritance - refactoring problem - possibility to create flexible service

It should be pretty easy but obviously I am lacking of basic knowlege.
I have a service which is ment to create ticket in BugTracking systems.
Creating plugins is pretty stright forward. there is an interface
public interface BugTracker {
boolean createAndSendIssue(Issue issue);
boolean updateAndSendIssue(Issue issue);
boolean closeIssue(Issue issue);
}
and API client for JIRA:
#Component
public class JiraClient implements BugTracker {
#Override
public boolean createAndSendIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
#Override
public boolean updateAndSendIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
#Override
public boolean closeIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
}
API CLient for Bugzilla:
#Component
public class BugzillaClient implements BugTracker {
#Override
public boolean createAndSendIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
#Override
public boolean updateAndSendIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
#Override
public boolean closeIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
}
Problem occurs on the Service which is handling MVC. Piece of it looks like:
#Service
public class BugTrackerService {
private final BugzillaClient bugzillaClient;
private final JiraClient jiraClient;
private static final String JIRA_TYPE = "Jira";
private static final String BUGZILLA_TYPE = "Bugzilla";
#Autowired
BugTrackerService(BugzillaClient bugzillaClient, JiraClient jiraClient) {
this.bugzillaClient = bugzillaClient;
this.jiraClient = jiraClient;
}
boolean processIssueTicketRequest(Issue issue){
if ( issue.getBugTrackerType().bugTrackingSystemType.name.equals(JIRA_TYPE)) {
return jiraClient.createAndSendIssue(issue);
} else if (issue.getBugTrackerType().bugTrackingSystemType.name.equals(BUGZILLA_TYPE)){
return bugzillaClient.createAndSendIssue(issue);
} else {
return false;
}
}
}
is it somehow possible to create method BugTrackerService.processIssueTicketRequest without all clients autowired? At this moment it is not so much of a problem but after integrating with more and more systems this service will become complex.
Depending on how reusable you want implementations to be, I'd probably put the logic of checking whether the given issue is of matching typing into the interface, eg
boolean canWorkWithGivenIssue(Issue issue);
With that in place then you don't need to know actual types of trackers you dispatch on, and merely aggregate them into the list. Spring will do that for you if you annotate a collection with #Autowired, in which cases it will provide you all the beans with matching type. Your service then could look like this
#Autowired List<BugTracker> trackers; //autowired on field for brevity
boolean processIssueTicketRequest(Issue issue){
for (BugTracker t : trackers)
if (t.canWorkWithGivenIssue(issue))
return t.createAndSendIssue(issue);
return false;
}
Turn the type into an enum and let the BugTracker decide if it can handle it. Then inject a collection of all BugTracker instances, iterate over them and if it supports the type call the appropriate method.
public enum SystemType { JIRA, BUGZILLA }
Then add a method, for instance supports(Issue issue), to your BugTracker.
boolean supports(Issue issue);
In the implementations check if it can be handled, for instance in the JiraClient do something like this.
public boolean supports(Issue issue) {
return JIRA == issue.getBugTrackerType();
}
Then in your BugTrackerService get a list of all BugTracker instances, iterate and call the appropriate one.
#Service
public class BugTrackerService {
private final List<BugTracker> bugTrackers;
BugTrackerService(List<BugTracker> bugTrackers) {
this.bugTrackers=bugTrackers;
}
boolean processIssueTicketRequest(Issue issue){
for (BugTracker bugTracker : this.bugTrackers) {
if (bugTracker.supports(issue) ) {
bugTracker.createAndSendIssue(issue);
return true;
}
}
return false;
}
}
Now you are as flexible as you want to be and can support as many as you want.
You can pass on the responsibility of finding out the correct implementation of BugTracker to a BugTrackerFactory.
#Component
class BugTrackerFactory {
#Autowired
private final BugzillaClient bugzillaClient;
#Autowired
private final JiraClient jiraClient;
private static final String JIRA_TYPE = "Jira";
private static final String BUGZILLA_TYPE = "Bugzilla";
public BugTracker getBugTracker(String type) {
if (JIRA_TYPE.equals(type)) {
return jiraClient;
} else if (BUGZILLA_TYPE.equals(type)) {
return bugzillaClient;
} else {
// throw some exception
}
}
}
BugTrackerService :
#Service
public class BugTrackerService {
private final BugTrackerFactory bugTrackerFactory;
#Autowired
BugTrackerService(BugTrackerFactory bugTrackerFactory) {
this.bugTrackerFactory = bugTrackerFactory;
}
boolean processIssueTicketRequest(Issue issue){
return bugTrackerFactory.getBugTracker(issue.getBugTrackerType().bugTrackingSystemType.name).createAndSendIssue(issue);
}
}

Dynamicaly instanciate class from name with injector

Context
I develop, for my company a software that classifies phishing and malware containing website thanks to multiple feature extraction algorithm.
Once features are extracted we use a pool of empirical and machine learning classifiers. We choose among them thanks to election function of our own.
the code
Basically we have our classifier classes that implement the AnalysisFunction contract.
public abstract class AnalysisFunction {
abstract public StatusType analyze(List<TokenEntity> tokens);
abstract public double getPhishingProbability(List<TokenEntity> tokens);
}
Our pool of classifier is contained by a "pool" that implements AnalysisFunction.
public class PoolAnalysisFunction extends AnalysisFunction{
private final List<AnalysisFunction> candidates;
private final ChoiceFunction choice;
private static final Logger LOG = LogManager.getLogger(PoolAnalysisFunction.class);
public PoolAnalysisFunction(List<AnalysisFunction> candidates, ChoiceFunction choice) {
this.candidates = candidates;
this.choice = choice;
}
#Override
public StatusType analyze(List<TokenEntity> tokens) {
try {
return choice.chooseAmong(candidates, tokens).analyze(tokens);
} catch (ImpossibleChoiceException e){
LOG.fatal("Not enough analysis function.", e);
return StatusType.CLEAN;
}
}
#Override
public double getPhishingProbability(List<TokenEntity> tokens) {
try {
return choice.chooseAmong(candidates, tokens).getPhishingProbability(tokens);
} catch (ImpossibleChoiceException e){
LOG.fatal("Not enough analysis function.", e);
return 0;
}
}
}
To ease the deployment and testing of new function, we want to make our pool fully customizable and instanciate every function by its name. To achieve this purpose we have a key in our property file that is like analysis.pool.functions=com.vadesecure.analysis.empirical.Function1,com.vadesecure.analysis.machine.AutomaticClassifier1.
I want to instantiate my functions thanks to that.
My problem is that those classifiers depend on different things such as custom configuration object and machine learning model.
I would like to inject those dependencies that are already bound in my hk2 injector.
import org.glassfish.hk2.api.Factory;
public class PoolFunctionFactory implements Factory<AnalysisFunction> {
private final PoolAnalysisParameters parameters;
private static final Logger LOG = LogManager.getLogger(PoolAnalysisFunction.class);
#Inject
public PoolFunctionFactory(PoolAnalysisParameters parameters) {
this.parameters = parameters;
}
#Override
public AnalysisFunction provide() {
try {
Class<?> choice = Class.forName(parameters.getChoiceFunctionFQDN());
ChoiceFunction choiceFunction = new PhishingPriorityChoiceFunction(); // default choice
if(choice.getSuperclass().isInstance(ChoiceFunction.class)){
choiceFunction = (ChoiceFunction) choice.newInstance();
}
List<AnalysisFunction> analysisFunctions = new LinkedList<>();
// I want to instantiate here
}
return new PoolAnalysisFunction(analysisFunctions, choiceFunction);
} catch (ClassNotFoundException|IllegalAccessException|InstantiationException e){
LOG.fatal(e, e);
}
return null;
}
#Override
public void dispose(AnalysisFunction analysisFunction) {
LOG.trace(String.format("%s end of life", analysisFunction));
}
}
On example of model-dependant classifier is :
public class SVMF2AnalysisFunction extends AnalysisFunction {
private final SVMContainer modelContainer;
private double probability = 0.0;
private double threshold = 0.9;
#Inject // i build this model in a parallel thread
public SVMF2AnalysisFunction(SVMContainer modelContainer) {
this.modelContainer = modelContainer;
}
#Override
public StatusType analyze(List<TokenEntity> tokens) {
if (modelContainer.getModel() == null) {
return null;
}
probability = modelContainer.getModel().analyse(tokens.stream());
return probability >= threshold ? StatusType.PHISHING : StatusType.CLEAN;
}
#Override
public double getPhishingProbability(List<TokenEntity> tokens) {
return probability;
}
}
How can I achieve those instanciations.
My first approach was to inject the serviceLocator but i found no documentations for doing this and a colleague said me it was not good.
He told be to document myself about proxies but it doesn't seem to be a good thing for me or perhaps I missed something.
You could just configure all this in your binder. This way you don't need to worry about trying to instantiate everything yourself. Just let HK2 do all the work
#Override
protected void configure() {
bindAsContract(PoolAnalysisFunction.class).in(Singleton.class);
bind(choiceFnClass).to(ChoiceFunction.class);
for (Class<AnalysisFunction> analysisFnClass: analyisFnClasses) {
bind(analysisFnClass).to(AnalysisFunction.class).in(Singleton.class);
}
}
Then you can just inject everything into the PoolAnalysisFunction class, without the need to use a factory.
#Inject
public PoolAnalysisFunction(IterableProvider<AnalysisFunction> candidates,
ChoiceFunction choice) {
this.choice = choice;
this.candidates = new ArrayList<>();
candidates.forEach(this.candidates::add);
}
Notice the IterableProvider class. This is an HK2 class for injecting multiple services bound to the same contract.
Or if you want to use the factory, you could, and just inject the functions into the factory. That way you can make the PoolAnalysisFunction class independent of an HK2 classes (i.e. the InjectableProvider).

Can I pass arguments into GWT Module constructor?

I have the following GWT module:
public class FizzModule implements EntryPoint {
private Buzz buzz;
public FizzModule() {
this(null);
}
public FizzModule(Buzz bz) {
super();
setBuzz(bz);
}
#Override
public void onModuleLoad() {
// ...etc.
}
}
I would like to "inject" FizzModule with a Buzz instance. However, all of the code examples I see for GWT modules do not use constructors. Instead, they bootstrap the DI mechanism (typically either ClientFactory or GIN) from inside the onModuleLoad() method. Is this something that GWT forces, or can I somehow inject my module before it loads to the client-side? Thanks in advance!
GWT instantiates your module using its zero-arg constructor, always.
(technically, I think it uses GWT.create() so you could use deferred binding rules, but that wouldn't change anything re. how its instantiated)
BTW, where would the Buzz instance come from?
You could add parameters to the URL and use PlaceController. Then get those values on module load.
public void onModuleLoad() {
SimplePanel mainPanel = new SimplePanel();
EventBus eventBus = GWT.creat(EventBus.class);
// Start ActivityManager for the main widget with ActivityMapper
ActivityManager activityManager = new ActivityManager(injector.getActivityMapper(),
eventBus);
activityManager.setDisplay(mainPanel);
RootPanel.get().add(mainPanel);
// Start PlaceHistoryHandler with our PlaceHistoryMapper
AppPlaceHistoryMapper contentHistoryMapper = GWT.create(AppPlaceHistoryMapper.class);
PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(contentHistoryMapper);
PlaceController placeController = new PlaceController(eventBus)
historyHandler.register(placeController, injector.getEventBus(), new MainPlace());
// Goes to the place represented on URL else default place
historyHandler.handleCurrentHistory();
if(placeController.getWhere() instanceof MainPlace) {
(MainPlace).getFoo();
}
}
public class MainPlace extends Place {
private String foo;
public MainPlace(String token) {
String foo = token;
}
#Override
public String getFoo() {
return foo;
}
public static class Tokenizer implements PlaceTokenizer<MainPlace> {
#Override
public MainPlace getPlace(String token) {
return new MainPlace(token);
}
#Override
public String getToken(MainPlace place) {
return place.getFoo();
}
}
}

Categories