Project

General

Profile

Download (11.6 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2017 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.addon.config;
10

    
11
import java.io.IOException;
12
import java.util.Arrays;
13
import java.util.List;
14
import java.util.Properties;
15

    
16
import javax.servlet.annotation.WebServlet;
17

    
18
import org.apache.log4j.Logger;
19
import org.hibernate.SessionFactory;
20
import org.hibernate.event.service.spi.EventListenerRegistry;
21
import org.hibernate.event.spi.EventType;
22
import org.hibernate.internal.SessionFactoryImpl;
23
import org.springframework.beans.BeansException;
24
import org.springframework.beans.factory.annotation.Autowired;
25
import org.springframework.context.ApplicationContext;
26
import org.springframework.context.ApplicationContextAware;
27
import org.springframework.context.annotation.Bean;
28
import org.springframework.context.annotation.ComponentScan;
29
import org.springframework.context.annotation.ComponentScan.Filter;
30
import org.springframework.context.annotation.Configuration;
31
import org.springframework.context.annotation.FilterType;
32
import org.springframework.core.env.Environment;
33
import org.springframework.security.authentication.AuthenticationProvider;
34

    
35
import com.vaadin.spring.annotation.EnableVaadin;
36
import com.vaadin.spring.annotation.SpringUI;
37
import com.vaadin.spring.annotation.UIScope;
38
import com.vaadin.spring.server.SpringVaadinServlet;
39
import com.vaadin.ui.UI;
40

    
41
import eu.etaxonomy.cdm.api.application.AbstractDataInserter;
42
import eu.etaxonomy.cdm.api.application.CdmRepository;
43
import eu.etaxonomy.cdm.api.application.DummyDataInserter;
44
import eu.etaxonomy.cdm.api.service.idminter.RegistrationIdentifierMinter;
45
import eu.etaxonomy.cdm.common.ConfigFileUtil;
46
import eu.etaxonomy.cdm.dataInserter.RegistrationRequiredDataInserter;
47
import eu.etaxonomy.cdm.opt.config.DataSourceConfigurer;
48
import eu.etaxonomy.cdm.persistence.hibernate.GrantedAuthorityRevokingRegistrationUpdateLister;
49
import eu.etaxonomy.cdm.vaadin.security.annotation.EnableAnnotationBasedAccessControl;
50
import eu.etaxonomy.cdm.vaadin.ui.ConceptRelationshipUI;
51
import eu.etaxonomy.cdm.vaadin.ui.DistributionStatusUI;
52
import eu.etaxonomy.cdm.vaadin.ui.RegistrationUI;
53
import eu.etaxonomy.cdm.vaadin.ui.StatusEditorUI;
54
import eu.etaxonomy.vaadin.ui.annotation.EnableVaadinSpringNavigation;
55

    
56
/**
57
 *
58
 * @author a.kohlbecker
59
 * @since Feb 8, 2017
60
 *
61
 */
62
@Configuration
63
@ComponentScan(basePackages={
64
        "eu.etaxonomy.vaadin.ui",
65
        "eu.etaxonomy.cdm.vaadin",
66
        "eu.etaxonomy.cdm.service",
67
        "org.springframework.context.event"
68
        },
69
        // exclude UI classes, these are provided via the @Bean annotated methods below
70
        excludeFilters={@Filter(
71
                pattern="eu\\.etaxonomy\\.cdm\\.vaadin\\.ui\\..*",
72
                type=FilterType.REGEX
73
                )
74
            })
75
@EnableVaadin   // this imports VaadinConfiguration
76
@EnableVaadinSpringNavigation // activate the NavigationManagerBean
77
@EnableAnnotationBasedAccessControl // enable annotation based per view access control
78
public class CdmVaadinConfiguration implements ApplicationContextAware  {
79

    
80

    
81
    public static final String CDM_DATA_SOURCE_ID = DataSourceConfigurer.CDM_DATA_SOURCE_ID;
82

    
83
    public static final String CDM_VAADIN_UI_ACTIVATED = "cdm-vaadin.ui.activated";
84
    public static final String CDM_SERVICE_MINTER_REGSTRATION_MINID = "cdm.service.minter.registration.minLocalId";
85
    public static final String CDM_SERVICE_MINTER_REGSTRATION_MAXID = "cdm.service.minter.registration.maxLocalId";
86
    public static final String CDM_SERVICE_MINTER_REGSTRATION_IDFORMAT = "cdm.service.minter.registration.identifierFormatString";
87

    
88
    public static final Logger logger = Logger.getLogger(CdmVaadinConfiguration.class);
89

    
90
    @Autowired
91
    Environment env;
92

    
93
    @Autowired
94
    private SessionFactory sessionFactory;
95

    
96
    private boolean registrationUiHibernateEventListenersDone = false;
97

    
98
    /*
99
     * NOTE: It is necessary to map the URLs starting with /VAADIN/* since none of the
100
     * @WebServlets is mapped to the root path. It is sufficient to configure one of the
101
     * servlets with this path see BookOfVaadin 5.9.5. Servlet Mapping with URL Patterns
102
     */
103
    @WebServlet(value = {"/app/*", "/VAADIN/*"}, asyncSupported = true)
104
    public static class Servlet extends SpringVaadinServlet {
105

    
106
        private static final long serialVersionUID = -2615042297393028775L;
107

    
108

    
109
        /**
110
         *
111
        @SuppressWarnings("serial")
112
        @Override
113
        protected void servletInitialized() throws ServletException {
114
            getService().addSessionInitListener(new SessionInitListener() {
115

    
116
                @Override
117
                public void sessionInit(SessionInitEvent sessionInitEvent) throws ServiceException {
118
                    VaadinSession session = sessionInitEvent.getSession();
119
                    session.setErrorHandler(new DefaultErrorHandler(){
120

    
121
                        @Override
122
                        public void error(ErrorEvent errorEvent) {
123
                            // ...
124
                        }
125

    
126
                    });
127
                    ).getServiceRegistry().getService
128

    
129
                }});
130

    
131
        }
132
         */
133

    
134
    }
135

    
136
    public CdmVaadinConfiguration() {
137
        logger.debug("CdmVaadinConfiguration enabled");
138
    }
139

    
140
    @Bean
141
    @UIScope
142
    public ConceptRelationshipUI conceptRelationshipUI() {
143
        if(isUIEnabled(ConceptRelationshipUI.class)){
144
            return new ConceptRelationshipUI();
145
        }
146
        return null;
147
    }
148

    
149
    @Bean
150
    @UIScope
151
    public RegistrationUI registrationUI() {
152
        if(isUIEnabled(RegistrationUI.class)){
153
            registerRegistrationUiHibernateEventListeners();
154

    
155
            return new RegistrationUI();
156
        }
157
        return null;
158
    }
159

    
160
    /**
161
     * this is only a quick implementation for testing,
162
     * TODO see also the NOTE on CdmListenerIntegrator class declaration for a prospective better solution
163
     */
164
    protected void registerRegistrationUiHibernateEventListeners() {
165
        if(!registrationUiHibernateEventListenersDone){
166
            EventListenerRegistry listenerRegistry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService(
167
                    EventListenerRegistry.class);
168
            GrantedAuthorityRevokingRegistrationUpdateLister listener = new GrantedAuthorityRevokingRegistrationUpdateLister();
169
            listenerRegistry.appendListeners(EventType.POST_UPDATE, listener);
170
            registrationUiHibernateEventListenersDone = true;
171
        }
172
    }
173

    
174
    @Bean
175
    public AbstractDataInserter registrationRequiredDataInserter() throws BeansException{
176
        if(isUIEnabled(RegistrationUI.class)){
177
            RegistrationRequiredDataInserter inserter = new RegistrationRequiredDataInserter();
178

    
179
            inserter.setRunAsAuthenticationProvider((AuthenticationProvider) applicationContext.getBean("runAsAuthenticationProvider"));
180
            inserter.setCdmRepository((CdmRepository) applicationContext.getBean("cdmRepository"));
181
            return inserter;
182
        } else {
183
            // the return type implements ApplicationListener and thus must not be null,
184
            // therefore we return a empty dummy implementation.
185
            return new DummyDataInserter();
186
        }
187
    }
188

    
189
    @Bean
190
    public RegistrationIdentifierMinter registrationIdentifierMinter() throws IOException {
191
        RegistrationIdentifierMinter minter = new RegistrationIdentifierMinter();
192
        ensureVaadinAppPropertiesLoaded();
193
        minter.setMinLocalId(appProps.getProperty(CDM_SERVICE_MINTER_REGSTRATION_MINID));
194
        minter.setMaxLocalId(appProps.getProperty(CDM_SERVICE_MINTER_REGSTRATION_MAXID));
195
        minter.setIdentifierFormatString(appProps.getProperty(CDM_SERVICE_MINTER_REGSTRATION_IDFORMAT));
196
        return minter;
197
    }
198

    
199
    @Bean
200
    @UIScope
201
    public DistributionStatusUI distributionStatusUI() {
202
        if(isUIEnabled(DistributionStatusUI.class)){
203
            return new DistributionStatusUI();
204
        }
205
        return null;
206
    }
207

    
208
    @Bean
209
    @UIScope
210
    public StatusEditorUI statusEditorUI() {
211
        if(isUIEnabled(StatusEditorUI.class)){
212
            return new StatusEditorUI();
213
        }
214
        return null;
215
    }
216

    
217

    
218

    
219

    
220
    static final String PROPERTIES_FILE_NAME = "vaadin-apps";
221

    
222
    private Properties appProps = null;
223

    
224
    private ApplicationContext applicationContext;
225

    
226
    private List<String> activeUIpaths;
227

    
228
    //@formatter:off
229
    private static final String APP_FILE_CONTENT=
230
            "########################################################\n"+
231
            "#                                                       \n"+
232
            "# Vaadin application specific configurations            \n"+
233
            "#                                                       \n"+
234
            "########################################################\n"+
235
            "                                                        \n"+
236
            "# Enablement of vaadin uis.                             \n"+
237
            "#                                                       \n"+
238
            "# Multiple uis can be defined as comma separated list.  \n"+
239
            "# Whitespace before and after the comma will be ignored.\n"+
240
            "# Valid values are the path properties of the @SpringUI \n"+
241
            "# annotation which is used for UI classes.              \n"+
242
            "cdm-vaadin.ui.activated=concept,distribution,editstatus \n";
243
    //@formatter:on
244

    
245
    /**
246
     * Checks if the ui class supplied is activated by listing it in the properties by its {@link SpringUI#path()} value.
247
     *
248
     * TODO see https://dev.e-taxonomy.eu/redmine/issues/7139 (consider using spring profiles to enable vaadin UI contexts)
249
     *
250
     * @param type
251
     * @return
252
     */
253
    private boolean isUIEnabled(Class<? extends UI>uiClass) {
254

    
255
        String path = uiClass.getAnnotation(SpringUI.class).path().trim();
256

    
257
        if(activeUIpaths == null){
258
            try {
259

    
260
                String activatedVaadinUIs = env.getProperty(CDM_VAADIN_UI_ACTIVATED);
261
                if(activatedVaadinUIs == null){
262
                    // not in environment? Read it from the config file!
263
                    ensureVaadinAppPropertiesLoaded();
264
                    if(appProps.get(CDM_VAADIN_UI_ACTIVATED) != null){
265
                        activatedVaadinUIs = appProps.get(CDM_VAADIN_UI_ACTIVATED).toString();
266
                    }
267
                }
268

    
269
                if(activatedVaadinUIs != null) {
270
                    String[] uiPaths = activatedVaadinUIs.split("\\s*,\\s*");
271
                    this.activeUIpaths = Arrays.asList(uiPaths);
272
                }
273
            } catch (IOException e) {
274
                logger.error("Error reading the vaadin ui properties file. File corrupted?. Stopping instance ...");
275
                throw new RuntimeException(e);
276
            }
277
        }
278
        if(activeUIpaths.stream().anyMatch(p -> p.trim().equals(path))){
279
            return true;
280
        }
281
        return false;
282

    
283
    }
284

    
285
    /**
286
     * @param currentDataSourceId
287
     * @throws IOException
288
     */
289
    protected void ensureVaadinAppPropertiesLoaded() throws IOException {
290

    
291
        String currentDataSourceId = env.getProperty(CDM_DATA_SOURCE_ID);
292
        if(appProps == null){
293
            appProps = new ConfigFileUtil()
294
                    .setDefaultContent(APP_FILE_CONTENT)
295
                    .getProperties(currentDataSourceId, PROPERTIES_FILE_NAME);
296
        }
297
    }
298

    
299
    /**
300
     * {@inheritDoc}
301
     */
302
    @Override
303
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
304
        this.applicationContext = applicationContext;
305
    }
306

    
307

    
308
}
(1-1/2)