Vaadin 7 : RPC call from Server to Client - vaadin

I would like to create custom image component .So I followed step by step from Integrating with Server-side. For basic or first-step , I created for the test Server to Client RPC call as following steps.
MyComponentWidget.java
public class MyComponentWidget extends HTML {
public MyComponentWidget() {
getElement().setAttribute("class", "thumbnail");
}
public final void createCustomImage(final String url) {
getElement().setInnerHTML("<div class='delete-block'></div><img src=" + url + " />");
}
}
MyComponentState.java
public class MyComponentState extends AbstractComponentState {
private String url;
private String html;
public final String getUrl() {
return url;
}
public final void setUrl(final String url) {
this.url = url;
}
public final String getHtml() {
return html;
}
public final void setHtml(final String html) {
this.html = html;
}
}
MyComponentConnector.java
public class MyComponentConnector extends AbstractComponentConnector {
public MyComponentConnector() {
registerRpc(MyComponentClientRpc.class, new MyComponentClientRpc() {
#Override
public void getMessage() {
// never reach to this place
System.err.println("Reach Here !");
getState().setHtml(getWidget().getHTML());
}
});
}
#Override
public final MyComponentWidget getWidget() {
return (MyComponentWidget) super.getWidget();
}
#Override
public final MyComponentState getState() {
return (MyComponentState) super.getState();
}
#OnStateChange("url")
final void updateText() {
getWidget().createCustomImage(getState().getUrl());
}
}
MyComponentClientRpc.java
import com.vaadin.shared.communication.ClientRpc;
public interface MyComponentClientRpc extends ClientRpc {
void getMessage();
}
MyComponent.java
public class MyComponent extends AbstractComponent {
public MyComponent(final String url) {
getState().setUrl(url);
}
public final MyComponentState getState() {
return (MyComponentState) super.getState();
}
public final String getHTML() {
getRpcProxy(MyComponentClientRpc.class).getMessage();
return getState().getHtml();
}
}
and call as
MyComponent image = new MyComponent("myImageUrl");
System.out.println(image.getHTML());
My problem is why I always get null value at my console ? I can see the image at browser but System.out.println(image.getHTML()); produces null. What am I missing ?

To make a rpc call from client to server, you must extend the ServerRpc interface, for example:
package com.example.client.MyServerRpc
public interface MyServerRpc extends com.vaadin.shared.communication.ServerRpc {
void sendHTML(String html);
}
In your connector your register the rpc:
private MyServerRpc rpc = RpcProxy.create(MyServerRpc.class, this);
And then you can send a value by using the registered rpc in your connector:
rpc.sendHTML(html);
To receive the value on your component's or extension's server-side class, you must create an instance of the rpc interface:
private MyServerRpc rpc = new MyServerRpc() {
#Override
public void sendHTML(String html) {
// this method will be called!
}
};
and register that in the constructor:
registerRpc(rpc);
After these steps RPC from client to server should work.

Related

Vaadin23 pass data between View and Layout

This is my view with ComponentEvent defined:
#Route(value = "jobs/recommended", layout = JobsLayout.class)
#PermitAll
public class RecommendedJobsView extends VerticalLayout implements HasUrlParameter<String> {
public static class JobableInfo {
private final Long profileId;
private final Long recommendedJobsCount;
public JobableInfo(Long profileId, Long recommendedJobsCount) {
this.profileId = profileId;
this.recommendedJobsCount = recommendedJobsCount;
}
public Long getProfileId() {
return profileId;
}
public Long getRecommendedJobsCount() {
return recommendedJobsCount;
}
#Override
public String toString() {
return "JobableInfo{" +
"profileId=" + profileId +
", recommendedJobsCount=" + recommendedJobsCount +
'}';
}
}
public static class ProfileRecommendedJobsEvent extends ComponentEvent<RecommendedJobsView> {
private final JobableInfo jobableInfo;
public ProfileRecommendedJobsEvent(RecommendedJobsView source, JobableInfo jobableInfo) {
super(source, false);
this.jobableInfo = jobableInfo;
}
public JobableInfo getJobableInfo() {
return jobableInfo;
}
}
this is Layout:
#ParentLayout(MainLayout.class)
public class JobsLayout extends VerticalLayout implements RouterLayout, LocaleChangeObserver, BeforeEnterObserver {
public JobsLayout() {
addListener(RecommendedJobsView.ProfileRecommendedJobsEvent.class, event -> {
System.out.println(event.getJobableInfo());
});
}
In RecommendedJobsView I fire an event in the following way:
fireEvent(new ProfileRecommendedJobsEvent(this, new JobableInfo(profileId, jobPage.getTotalElements())));
but nothing happens in the JobsLayout. The listener doesn't react. What am I doing wrong and how to correctly send data from RecommendedJobsView to JobsLayout ?

Injecting HttpService into a Mule 4 Custom Configuration Properties Provider

I'm working on making a custom properties provider to load the contents of a Spring cloud config server at startup. I need to make a single call at the initialization of the provider to fetch these properties, and would like to use the Mule HttpService in order to make the http client for this call, instead of creating my own. Unfortunately, whenever I try this, it seems the HttpService hasn't been created yet and so throws an NPE once it's referenced.
CustomConfigurationPropertiesProviderFactory.java
public class CustomConfigurationPropertiesProviderFactory implements ConfigurationPropertiesProviderFactory {
public static final String EXTENSION_NAMESPACE = "custom-properties";
public static final String CONFIGURATION_PROPERTIES_ELEMENT = "config";
public static final ComponentIdentifier CUSTOM_CONFIGURATION_PROPERTIES =
builder().namespace(EXTENSION_NAMESPACE).name(CONFIGURATION_PROPERTIES_ELEMENT).build();
#Inject
HttpService httpService;
#Override
public ComponentIdentifier getSupportedComponentIdentifier() {
return CUSTOM_CONFIGURATION_PROPERTIES;
}
#Override
public ConfigurationPropertiesProvider createProvider(ConfigurationParameters parameters,
ResourceProvider externalResourceProvider) {
String url = parameters.getStringParameter("url");
return new CustomConfigurationPropertiesProvider(url, httpService);
}
}
CustomConfigurationPropertiesProvider.java
public class CustomConfigurationPropertiesProvider implements ConfigurationPropertiesProvider {
private final static String PREFIX = "custom::";
private Properties properties = null;
public CustomConfigurationPropertiesProvider(String url, HttpService httpService) {
HttpClientConfiguration.Builder builder = new HttpClientConfiguration.Builder();
builder.setName("customProperties");
HttpClient client = httpService.getClientFactory().create(builder.build()); //NPE here
client.start();
// proceed to create and execute request, then load into properties
}
#Override
public Optional<ConfigurationProperty> getConfigurationProperty(String configurationAttributeKey) {
if (configurationAttributeKey.startsWith(PREFIX)) {
String effectiveKey = configurationAttributeKey.substring(PREFIX.length());
if (properties != null && !properties.isEmpty()) {
return Optional.of(new ConfigurationProperty() {
#Override
public Object getSource() {...}
#Override
public Object getRawValue() { return properties.getProperty(effectiveKey); }
#Override
public String getKey() { return effectiveKey; }
});
}
}
return Optional.empty();
}
}
What do I need to change to properly inject this service?
I've been following the advice from these two bits of documentation, for reference:
https://docs.mulesoft.com/mule-runtime/4.2/custom-configuration-properties-provider
https://docs.mulesoft.com/mule-sdk/1.1/mule-service-injection

Jersy2 inject slf4j Logger

I'm trying to understand Jersey 2 development and context-dependency injection.
I don't understand how to inject into a resource an object that needs initialization parameters in the constructor.
For example: I'd like to #Inject slf4j Logger, built using LoggerFactory.
My resource class is:
#Path("/myresource")
public class MyResource {
#Inject
private Logger log;
#GET
#Produces(MediaType.APPLICATION_JSON)
public Answer status() {
log.info("STATUS");
return new Answer(200, "Server up and running # "+ ZonedDateTime.now());
}
}
My Resource config is:
public class MyAppextends ResourceConfig {
public MyApp() {
register(new MyBinder());
packages(true, "my.packages");
}
}
public class MyBinder extends AbstractBinder {
#Override
protected void configure() {
bindFactory(MyLoggerFactory.class).to(org.slf4j.Logger.class);
}
}
Finally, the Factory is:
public class MyLoggerFactory implements Factory<Logger> {
#Override
public Logger provide() {
return LoggerFactory.getLogger(TYPE_FOR_LOGGING.class);
}
#Override
public void dispose(Logger logger) {
}
}
How can I specify TYPE_FOR_LOGGING as argument, in order to Inject the correctly initialized Logger in every resource I want?
Thanks
What you are looking for is called the InstantiationService. You can inject it into Factories to find out who is calling the factory inside of the provide method.
Below find a code sample from the hk2 tests that illustrate the use of the InstantiationService.
#Singleton
public class CorrelationFactory implements Factory<PerLookupServiceWithName> {
private final static PerLookupServiceWithName NULL_SERVICE = new PerLookupServiceWithName() {
#Override
public String getName() {
return null;
}
};
#Inject
private InstantiationService instantiationService;
/* (non-Javadoc)
* #see org.glassfish.hk2.api.Factory#provide()
*/
#Override #PerLookup
public PerLookupServiceWithName provide() {
InstantiationData data = instantiationService.getInstantiationData();
if (data == null) {
return NULL_SERVICE;
}
Injectee parent = data.getParentInjectee();
if (parent == null) {
return NULL_SERVICE;
}
Class<?> parentClass = parent.getInjecteeClass();
if (parentClass == null) {
return NULL_SERVICE;
}
Correlator correlator = parentClass.getAnnotation(Correlator.class);
if (correlator == null) {
return NULL_SERVICE;
}
final String fName = correlator.value();
return new PerLookupServiceWithName() {
#Override
public String getName() {
return fName;
}
};
}
/* (non-Javadoc)
* #see org.glassfish.hk2.api.Factory#dispose(java.lang.Object)
*/
#Override
public void dispose(PerLookupServiceWithName instance) {
// DO nothing
}
}

NestedSlot presenter with own url- how to setup url for NestedSlot presenters

I have parent presenter: UsersListPresenter that contains nested presenter: UserPresenter in NestedSlot.
public class UsersListPresenter extends ApplicationPresenter<UsersListPresenter.MyView, UsersListPresenter.MyProxy> implements UsersListUiHandlers,
OpenWindowEvent.OpenModaHandler, UserAddedEvent.UserAddedHandler {
#ProxyStandard
#NameToken(ClientRouting.Url.users)
#UseGatekeeper(IsUserLoggedGatekeeper.class)
public interface MyProxy extends TabContentProxyPlace<UsersListPresenter> {}
#TabInfo(container = AppPresenter.class)
static TabData getTabLabel(IsUserLoggedGatekeeper adminGatekeeper) {
return new MenuEntryGatekeeper(ClientRouting.Label.users, 1, adminGatekeeper);
}
public interface MyView extends View, HasUiHandlers<UsersListUiHandlers> {
void setUsers(List<UserDto> users);
void addUser(UserDto user);
}
public static final NestedSlot SLOT_USER_WINDOW = new NestedSlot();
//interface Driver extends SimpleBeanEditorDriver<UserDto, UserEditor> {}
private static final UserService userService = GWT.create(UserService.class);
private AppPresenter appPresenter;
private UserTestPresenter userPresenter;
#Inject
UsersListPresenter(EventBus eventBus, MyView view, MyProxy proxy, AppPresenter appPresenter, UserTestPresenter userPresenter) {
super(eventBus, view, proxy, appPresenter, AppPresenter.SLOT_TAB_CONTENT);
this.appPresenter = appPresenter;
this.userPresenter = userPresenter;
getView().setUiHandlers(this);
}
#Override
protected void onBind() {
super.onBind();
updateList();
setInSlot(SLOT_USER_WINDOW, userPresenter);
addRegisteredHandler(OpenWindowEvent.getType(), this);
}
#Override
protected void onReveal() {
super.onReveal();
initializeApplicationUiComponents(ClientRouting.Label.users);
}
#Override
public void onOpenModal(OpenWindowEvent event) {
openModal(event.getUser());
}
#Override
public void openModal(UserDto user) {
userPresenter.openModal(user);
}
}
public class UsersListView extends ViewWithUiHandlers<UsersListUiHandlers> implements UsersListPresenter.MyView {
interface Binder extends UiBinder<Widget, UsersListView> {}
#UiField
SimplePanel windowSlot;
#Inject
UsersListView(Binder uiBinder) {
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public void setInSlot(Object slot, IsWidget content) {
if (slot == UsersListPresenter.SLOT_USER_WINDOW) {
windowSlot.setWidget(content);
}
};
}
public class UserTestPresenter extends Presenter<UserTestPresenter.MyView, UserTestPresenter.MyProxy> implements UserTestUiHandlers {
public interface MyView extends View, HasUiHandlers<UserTestUiHandlers> {
void openModal(UserDto user);
}
#ProxyStandard
#NameToken("/user/{userid}")
public interface MyProxy extends ProxyPlace<UserTestPresenter> {
}
private PlaceManager placeManager;
#Inject
public UserTestPresenter(EventBus eventBus, MyView view, MyProxy proxy, PlaceManager placeManager) {
super(eventBus, view, proxy, UsersListPresenter.SLOT_USER_WINDOW);
this.placeManager = placeManager;
getView().setUiHandlers(this);
}
#Override
public void prepareFromRequest(PlaceRequest request) {
GWT.log("Prepare from request " + request.getNameToken());
}
#Override
protected void onReveal() {
super.onReveal();
};
public void openModal(UserDto user) {
getView().openModal(user);
}
#Override
public void onSave(UserDto user) {
// TODO Auto-generated method stub
MaterialToast.fireToast("onSaveClick in new presenter for " + user.toString());
}
#Override
public void onClose() {
PlaceRequest placeRequest = new PlaceRequest.Builder().nameToken("/users/{userid}").with("userid", "list").build();
placeManager.revealPlace(placeRequest);
}
public class UserTestView extends ViewWithUiHandlers<UserTestUiHandlers> implements UserTestPresenter.MyView {
interface Binder extends UiBinder<Widget, UserTestView> {}
#UiField
MaterialRow main;
#UiField
MaterialWindow window;
#UiField
MaterialLabel userName, userFullName;
#UiField
MaterialButton saveButton;
private HandlerRegistration saveButtonClickHandler;
#Inject
UserTestView(Binder uiBinder) {
initWidget(uiBinder.createAndBindUi(this));
// adding default click handler
saveButtonClickHandler = saveButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {}
});
}
#Override
public void openModal(final UserDto user) {
userName.setText(user.getEmail());
userFullName.setText(user.getId() + " " + user.getEmail());
saveButtonClickHandler.removeHandler();
saveButtonClickHandler = saveButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
getUiHandlers().save(user);
}
});
window.openWindow();
}
}
when user from list is clicked the window with clicked users is opened. At this moment url should change from http://localhost:8080/cms/#/users/list to http://localhost:8080/cms/#/user/3
for better understanding below is screencast from that code:
and now some job done, but still not ideal:
here is my gwtp configuration:
public class ClientModule extends AbstractPresenterModule {
#Override
protected void configure() {
bind(RestyGwtConfig.class).asEagerSingleton();
install(new Builder()//
.defaultPlace(ClientRouting.HOME.url)//
.errorPlace(ClientRouting.ERROR.url)//
.unauthorizedPlace(ClientRouting.LOGIN.url)//
.tokenFormatter(RouteTokenFormatter.class).build());
install(new AppModule());
install(new GinFactoryModuleBuilder().build(AssistedInjectionFactory.class));
bind(CurrentUser.class).in(Singleton.class);
bind(IsAdminGatekeeper.class).in(Singleton.class);
bind(IsUserLoggedGatekeeper.class).in(Singleton.class);
bind(ResourceLoader.class).asEagerSingleton();
}
}
As You can see I use tokenFormatter(RouteTokenFormatter.class)
how it can be achieved with gwtp framework?
One way to achieve this is to change the URL of your UserListPresenter to support passing in the user id as an optional parameter:
#NameToken("/users/{userid}")
public interface MyProxy extends ProxyPlace<UserListPresenter> {
}
You need to override the prepareFromRequest method of your UserListPresenter and there you check if the userid is set and open your modal window if it is.
#Override
public void prepareFromRequest(PlaceRequest request) {
String userid = request.getParameter("userid", "list");
if (userid != "list") {
# open modal
}
else {
# close modal
}
}
You also need to change the logic when you click your on a user in your list:
#Override
public void onOpenModal(OpenWindowEvent event) {
PlaceRequest placeRequest = new PlaceRequest.Builder()
.nameToken("/users/{userid}")
.with("userid", event.getUser().getId())
.build();
placeManager.revealPlace(placeRequest);
}
This will change the URL and open the modal.

Basic Authentication service called By Zuul

I'm Zuul as edge server. so all request pass by this edge server.
I have a micro-service A. all web services of A are protected by Basic Authentication.
How can we call the services of A b passing by Zuul proxy?
Should I add header for messages?
This is my Zuul filter:
public class BasicAuthorizationHeaderFilter extends ZuulFilter {
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 10;
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.getRequest().getRequestURL();
ctx.addZuulRequestHeader("Authorization", "Basic " + Utils.getBase64Credentials("user", "Token"));
return null;
}
}
Ideally the requester would have the token in the request.
If you want to have Zuul add the authentication token then you can create a ZuulFilter and use:
context.addZuulRequestHeader("Authorization", "base64encodedTokenHere");
Doing this would give open access to the services - which may not be wise.
#Component
public class PreFilter extends ZuulFilter {
private static final Logger LOG = LoggerFactory.getLogger(PreFilter.class);
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 1;
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
ctx.addZuulRequestHeader("Authorization", request.getHeader("Authorization"));
LOG.info("Parametres : {}", request.getParameterMap()
.entrySet()
.stream()
.map(e -> e.getKey() + "=" + Stream.of(e.getValue()).collect(Collectors.toList()))
.collect(Collectors.toList()));
LOG.info("Headers : {}", "Authorization" + "=" + request.getHeader("Authorization"));
LOG.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
return null;
}
}
You can call (through Zuul) your service A like this :
https://login:password#zuulurl.com/serviceA
but firslty allow AUTHORIZATION header through Zuul for this specific service (route) with the property sensitiveHeaders in your properties file :
zuul.routes.serviceA.sensitiveHeaders=Cookie,Set-Cookie
or let it empty if you want to pass the Cookie headers too.
Here more informations about headers through Zuul
Use zuul's sensitive header property with the blank value,
zuul.sensitiveHeaders=
Above property will do the trick but if you want to have filters for Cookie headers
you can use that property with values,
zuul.sensitiveHeaders=Cookie,Set-Cookie
This change is little tricky.
#Override
public int filterOrder() {
return 1; // change the return value to more than 5 the above code will work.
}
try with the final code below:
#Component
public class PreFilter extends ZuulFilter {
private static final Logger LOG = LoggerFactory.getLogger(PreFilter.class);
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 10;
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
ctx.addZuulRequestHeader("Authorization", request.getHeader("Authorization"));
return null;
}
}

Resources