Injecting fragment and configuration change handling - dependency-injection

public class HostActivity extends Activity {
#Inject HostedFragment fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_host);
ObjectGraph.create(new HostActivityModule()).inject(this);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction().add(R.id.fragment_container, fragment).commit();
}
}
public static class HostedFragment extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_hosted, container, false);
}
}
#Module(injects = HostActivity.class)
public static class HostActivityModule {
#Provides #Singleton
HostedFragment provideHostedFragment() {
return new HostedFragment();
}
}
}
In a new project, I start to use dagger and nested fragment and come got a 2 questions in my mind.
1. Should fragment be injected into activity or another fragment?
2. What is the correct way to inject fragment which handle recreation after configuration change?
The problem I encounter is in the above code, another HostedFragment will be created and injected into HostActivity.
if (savedInstanceState == null) {
ObjectGraph.create(new HostActivityModule()).inject(this);
getFragmentManager().beginTransaction().add(R.id.fragment_container, fragment).commit();
}
Modifying to the above version might avoid duplicate HostedFragment being created but if we need injections other then fragment, they are not injected during recreation.
Can anyone help me?

I come up with an approach, am I correct?
The only thing bother me is if HostedFragment is not specified in the #Module inject, I cannot get it from the graph.
public class HostActivity extends Activity {
private static final String FRAGMENT_TAG = "fragment tag";
private ObjectGraph objectGraph;
private HostedFragment fragment;
#Inject LocationManager locationManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_host);
// Injecting fields that are required
objectGraph = ObjectGraph.create(new HostActivityModule(this));
objectGraph.inject(this);
// Injecting fragment
fragment = (HostedFragment) getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
if (fragment == null) {
fragment = objectGraph.get(HostedFragment.class);
getFragmentManager().beginTransaction().add(R.id.fragment_container, fragment, FRAGMENT_TAG).commit();
}
}
public static class HostedFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_hosted, container, false);
}
}
#Module(
injects = {
HostActivity.class,
HostedFragment.class
},
library = true
)
public static class HostActivityModule {
private Context mContext;
public HostActivityModule(Context mContext) {
this.mContext = mContext;
}
#Provides #Singleton HostedFragment provideHostedFragment() {
return new HostedFragment();
}
#Provides #Singleton LocationManager provideLocationManager() {
return (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
}
}
}

Related

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.

Commit EntityManager Transaction using #Transactional - Guice

I'm using Guice to Inject EntityManager.
When I commit the trasaction of the injected entityManager there is nothing happend in the BD side : no transaction passed !!! can you help me to figure out what is going on ?
Here is my code :
Web.xml
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>ca.products.services.InjectorListener</listener-class>
</listener>
The InjectorListener class :
public class InjectorListener extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
return Guice.createInjector(
new PersistenceModule(),
new GuiceModule(),
new RestModule());
}
}
The persistenceModule class :
public class PersistenceModule implements Module {
#Override
public void configure(Binder binder) {
binder
.install(new JpaPersistModule("manager1")
.properties(getPersistenceProperties()));
binder.bind(PersistenceInitializer.class).asEagerSingleton();
}
private static Properties getPersistenceProperties() {
Properties properties = new Properties();
properties.put("hibernate.connection.driver_class", "org.postgresql.Driver");
properties.put("hibernate.connection.url", "jdbc:postgresql://localhost:5432/postgres");
properties.put("hibernate.connection.username", "postgres");
properties.put("hibernate.connection.password", "postgres");
properties.put("hibernate.connection.pool_size", "1");
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.hbm2ddl.auto", "create");
return properties;
}
}
The GuiceModule class :
public class GuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(MemberRepository.class).to(MemberRepositoryImp.class);
bind(ProductRepository.class).to(ProductRepositoryImpl.class);
bind(ShoppingBagRepository.class).to(ShoppingBagRepositoryImpl.class);
}
}
The RestModule class :
public class RestModule extends JerseyServletModule {
#Override
protected void configureServlets() {
HashMap<String, String> params = new HashMap<>();
params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "ca.products.services");
params.put(JSONConfiguration.FEATURE_POJO_MAPPING, "true");
params.put(ResourceConfig.FEATURE_DISABLE_WADL, "true");
serve("/*").with(GuiceContainer.class, params);
}
}
and Finally the webservice (jeresy) call:
#Inject
private Provider<EntityManager> em;
#GET
#Transactional
#Path("/reset")
public void resetData() {
logger.info("Processing reset");
try {
em.get().getTransaction().begin();
for (int i = 0; i < 10; i++) {
em.get().persist(new Product("Product_" + i, "Desc_" + i));
}
em.get().flush();
em.get().getTransaction().commit();
} catch (Exception e) {
throw new WebApplicationException(Response.Status.FORBIDDEN);
}
}
You probably need to add the a persist filter. This will also keep you from having to manage transactions manually. If you do not use the filter you can still inject the UnitOfWork to create transactions. If you are using jpa persist you should not be managing userTransactions.
This is a custom filter that also adds a Lifecycle which it automatically started on startup with some custom code and a map binder builder. It is only there for thoroughness. It is not part of the guice api but more similar to spring's Lifecycle listener. I don't have any spring dependencies at all.
#Singleton
public final class JpaPersistFilter implements Filter {
private final UnitOfWork unitOfWork;
private final PersistServiceLifecycle persistService;
#Inject
public JpaPersistFilter(UnitOfWork unitOfWork, PersistServiceLifecycle persistService) {
this.unitOfWork = unitOfWork;
this.persistService = persistService;
}
public void init(FilterConfig filterConfig) throws ServletException {
// persistService.start();
}
public void destroy() {
persistService.stop();
}
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
unitOfWork.begin();
try {
filterChain.doFilter(servletRequest, servletResponse);
} finally {
unitOfWork.end();
}
}
/**
* Extra lifecycle handler for starting and stopping the service. This
* allows us to register a {#link Lifecycle} with the
* {#link LifecycleListener} and not have to worry about the service being
* started twice.
*
* #author chinshaw
*
*/
#Singleton
public static class PersistServiceLifecycle implements Lifecycle {
private final PersistService persistService;
private volatile boolean isStarted = false;
#Inject
public PersistServiceLifecycle(PersistService persistSerivce) {
this.persistService = persistSerivce;
}
#Override
public boolean isRunning() {
return isStarted;
}
#Override
public void start() {
if (!isStarted) {
persistService.start();
isStarted = true;
}
}
#Override
public void stop() {
persistService.stop();
isStarted = false;
}
}
}
Example of adding filter to module.
#Override
protected void configureServlets() {
filter("/api/*").through(JpaPersistFilter.class);
}
Example of using unit of work to manage the transaction.
#Inject
UnitOfWork unitOfWork;
public void doSomething() {
unitOfWork.begin();
try {
dao.saveState(someobject);
} finally {
unitOfWork.end();
}
}

Managing and loading assets via AssetManager (Libgdx)

Im having some issues with the AssetManager provided by Libgdx.
I get a nullpointer:
Java.lang.IllegalArgumentException: texture cannot be null.
at com.badlogic.gdx.graphics.g2d.TextureRegion.<init>(TextureRegion.java)
at com.test.test.screens.screens.MainScreen.show(MainScreen.java)
at com.badlogic.gdx.Game.setScreen(Game.java)
at com.test.test.screens.screens.SplashScreen.render(SplashScreen.java)
I´ve checked and the file it´s loading is present and correct, so it´s something in my code. And I literally have no idea what to do about it.. I was told to make sure I create not a new instance of Assets but creating an existing instance of it. Not sure if I´ve done it correctly though..
This is the class it self:
public class Assets {
public final AssetManager manager = new AssetManager();
private ObjectMap<String, Texture> textures;
private ObjectMap<String, Sound> sounds;
public final String background = "test.jpg";
public Assets() {
textures = new ObjectMap<String, Texture>();
sounds = new ObjectMap<String, Sound>();
manager.load(background, Texture.class);
}
public boolean update() {
boolean done = manager.update();
if (done) {
finishLoading();
}
return done;
}
private void finishLoading() {
textures.put(background, manager.get(background, Texture.class));
}
public Texture getTexture(String name) {
return textures.get(name);
}
public void dispose() {
manager.clear();
}
}
And at the moment I declare it like this in my MainClass:
public class MainClass extends Game {
public SpriteBatch batch;
public purchaseInterface pi;
//Calls the Assets to be implemented in other classes
public Assets assets;
public MainClass(purchaseInterface purchase, GalleryOpener opener){
this.gallery= opener;
this.pi = purchase;
}
#Override
public void create () {
batch = new SpriteBatch();
assets = new Assets();
setScreen(new SplashScreen(this));
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
}
#Override
public void render () {
super.render();
}
#Override
public void dispose() {
super.dispose();
batch.dispose();
assets.dispose();
}
public Assets getAssets() {
return assets;
}
#Override
public void pause() {
super.pause();
}
#Override
public void resume() {
// TODO Auto-generated method stub
super.resume();
}
}
And for the example of loading assets to a Screen class:
public Assets assets;
public MainScreen(MainClass gam) {
game = gam;
assets = game.getAssets();
loadStore();
camera = new OrthographicCamera(screenWidth,screenHeight);
view = new StretchViewport(screenWidth, screenHeight, camera);
view.apply();
camera.translate(camera.viewportWidth / 2, camera.viewportHeight / 2);
}
public void loadStore() {
background = assets.getTexture(assets.background);
}
#Override
public void render(float delta) {
camera.update();
game.batch.setProjectionMatrix(camera.combined);
game.batch.begin();
game.batch.draw(background, 0, 0, 1000, 2000);
game.batch.end();
}
#Override
public void resize(int width, int height) {
view.update(width, height, true);
}
#Override
public void show() {
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
}
#Override
public void dispose() {
background.dispose();
}
}
This will NOT load the background texture:
manager.load(background, Texture.class);
You need call the
manager.finishLoading();
right after the load() for that. AssetManager.load() is just store the path of an asset. AssetManager.update() loads the next item from the stored paths in an other thread, AssetManager.finishLoading() loads ALL of the items and waits for the loading thread to finish. When you would like to draw an image while you loading the other assets, you need to load first that image (in this case the "background").
The other thing, I think you store things twice for nothing (textures, sounds objectmaps). The best practice is use the asset manager to get the textures or any assets with the "get" function.
I did this:
public class LoadingScreen extends Screen {
...
#Override
public void show() {
app.assets.load("data/textures/loading.pack", TextureAtlas.class);
app.assets.finishLoading(); // this is waits for the loading finish
app.assets.load("data/textures/menu.pack", TextureAtlas.class);
app.assets.load("data/textures/sprites.pack", TextureAtlas.class);
...
}
#Override
public void render(float delta) {
if (app.assets.update()) { // this is loads the next item in an other thread
app.loadingFinished(); // this is where you will create the other screens
}
...
}
...
"app" is a Game instance, "app.assets" is an AssetManager instance. When I want to have an asset I do this (but this only can run after loading is finished!):
TextureAtlas atlas = app.assets.get("data/textures/sprites.pack", TextureAtlas.class);

How to change the main view of a Vaadin 7 application?

I want to write a Vaadin 7 application (see MyVaadinUI below), which asks the user to enter user name and password.
If they are correct, another view (see MainUI below) should appear and take the entire area (replace the login view).
I tried to implement this transition in the method MyVaadinUI.goToMainWindow, but I get the error
java.lang.RuntimeException: Component must be attached to a session when getConnectorId() is called for the first time
at com.vaadin.server.AbstractClientConnector.getConnectorId(AbstractClientConnector.java:417)
at com.vaadin.server.communication.ConnectorHierarchyWriter.write(ConnectorHierarchyWriter.java:67)
at com.vaadin.server.communication.UidlWriter.write(UidlWriter.java:143)
at com.vaadin.server.communication.UidlRequestHandler.writeUidl(UidlRequestHandler.java:149)
at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:97)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:37)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1371)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:238)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
when I run the application and press the button.
How can I fix it?
#Theme("mytheme")
#SuppressWarnings("serial")
public class MyVaadinUI extends UI
{
private TextField userNameTextField;
private PasswordField passwordTextField;
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = MyVaadinUI.class, widgetset = "ru.mycompany.vaadin.demo.AppWidgetSet")
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
addUserNameTextField(layout);
addPasswordTextField(layout);
addButton(layout, request);
}
private void addPasswordTextField(Layout aLayout) {
passwordTextField = new PasswordField("Пароль:");
aLayout.addComponent(passwordTextField);
}
private void addUserNameTextField(final Layout aLayout) {
userNameTextField = new TextField("Пользователь:");
aLayout.addComponent(userNameTextField);
}
private void addButton(final Layout aParent, final VaadinRequest request) {
final Button button = new Button("Войти");
button.addClickListener(new Button.ClickListener() {
public void buttonClick(Button.ClickEvent event) {
final boolean credentialsCorrect = checkCredentials();
if (credentialsCorrect) {
goToMainWindow(request);
} else {
[...]
}
}
});
aParent.addComponent(button);
}
private void goToMainWindow(final VaadinRequest aRequest) {
final MainUI mainUI = new MainUI();
mainUI.init(aRequest);
setContent(mainUI);
}
}
#Theme("mytheme")
#SuppressWarnings("serial")
public class MainUI extends UI {
#Override
protected void init(final VaadinRequest vaadinRequest) {
final HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
setContent(splitPanel);
splitPanel.setSizeFull();
splitPanel.setSplitPosition(200, Unit.PIXELS);
final String[] tabLabels = new String[] {
"Tree item 1",
"Tree item 2"};
final Tree tree = new Tree();
for (int i=0; i < tabLabels.length; i++)
{
addTreeItem(tree, tabLabels[i]);
}
splitPanel.setFirstComponent(tree);
splitPanel.setSecondComponent(new Label("Test"));
}
private void addTreeItem(final Tree aTree, final String aLabel) {
aTree.addItem(aLabel);
}
}
On the Vaadin forum someone suggested to use the navigator, which solved my problem.
I'd rather think that MainUI should extend HorizontalSplitPanel, not UI. It is strange concept to me to insert one UI into another.
You can use #SpringUI for the main class which extends UI:
#SpringUI
#Theme("mytheme")
#Widgetset("com.MyAppWidgetset")
#PreserveOnRefresh
public class MainUI extends UI {
private static final long serialVersionUID = -8247521108438815011L;
private static Locale locale = VaadinSession.getCurrent().getLocale();
#Autowired
private ToolBoxMessageSource messageSource;
#Autowired
private SpringViewProvider springViewProvider;
public MainUI() {
}
//Initializes navigator with SpringViewProvider and add all existing
//and ui specific assigned views to navigator.
#Override
protected void init(VaadinRequest vaadinRequest) {
Navigator navigator = new Navigator(this, this);
// Adding springViewProvider for spring autowiring
navigator.addProvider(springViewProvider);
// Adding all views for navigation
navigator.addView(LoginView.NAME, LoginView.class);
navigator.addView(MainView.NAME, MainView.class);
navigator.addView(MailToolView.NAME, MailToolView.class);
navigator.addView(AdminView.NAME, AdminView.class);
navigator.addView(EditRecipientView.NAME, EditRecipientView.class);
navigator.addView(EditRecipientsView.NAME, EditRecipientsView.class);
navigator.addView(ServerView.NAME, ServerView.class);
navigator.addView(TestJobView.NAME, TestJobView.class);
navigator.addView("", new LoginView());
navigator.navigateTo(LoginView.NAME);
navigator.setErrorView(LoginView.class);
// security: if user changes view check if the user has the required rights
navigator.addViewChangeListener(new ViewChangeListener() {
private static final long serialVersionUID = 7330051193056583546L;
#Override
public boolean beforeViewChange(ViewChangeEvent event) {
Toolbox toolbox = getSession().getAttribute(Toolbox.class);
if (TbRightManagement.checkAccess(event.getNewView().getClass(), toolbox)) {
return true;
} else {
if (toolbox != null) {
TBNotification.show(messageSource.getMessage("access.denied.title", locale),
messageSource.getMessage("access.denied.no_permissions.msg", locale),
Type.ERROR_MESSAGE);
navigator.navigateTo(MainView.NAME);
return false;
} else {
TBNotification.show(messageSource.getMessage("access.denied.title", locale),
messageSource.getMessage("access.denied.not_loggedin.msg", locale),
Type.ERROR_MESSAGE);
navigator.navigateTo(LoginView.NAME);
return false;
}
}
}
#Override
public void afterViewChange(ViewChangeEvent event) {}
});
}
}
And for the other views, as an example EditRecipientsView should be a #SpringView which extends a Vaadin Designer and implements a Vaadin View.
#SpringView(name = EditRecipientsView.NAME)
#Theme("mytheme")
#TbRight(loggedIn = true, mailTool = true)
public class EditRecipientsView extends RecipientsDesign implements View {
private static final long serialVersionUID = 1L;
public static final String NAME = "editRecipients";
private static Locale locale = VaadinSession.getCurrent().getLocale();
private BeanItemContainer<Recipient> recipientContainer;
private Uploader uploader;
#Autowired
private ToolBoxMessageSource messageSource;
public EditRecipientsView() {
super();
}
//Initializes the ui components of the recipient view.
#PostConstruct
public void init() {
btn_addRecipient.addClickListener(e -> { MainUI.getCurrent().getNavigator().navigateTo(EditRecipientView.NAME);});
}
//Handling data when entering this view.
#Override
public void enter(ViewChangeEvent event) {
if (getSession().getAttribute(UIMailing.class) != null) {
List<Recipient> recipientList = getSession().getAttribute(UIMailing.class).getRecipients();
if (recipientList != null) {
recipientContainer.removeAllItems();
} else {
recipientList = new ArrayList<Recipient>();
}
recipientContainer.addAll(recipientList);
recipient_table.sort(new Object[] {"foreName", "lastName"}, new boolean[] {true, true});
}
}
}

Resources