View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.persistence.jpa.content;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.Properties;
24  import javax.sql.DataSource;
25  import javax.xml.XMLConstants;
26  import javax.xml.parsers.ParserConfigurationException;
27  import javax.xml.parsers.SAXParser;
28  import javax.xml.parsers.SAXParserFactory;
29  import org.apache.syncope.core.persistence.api.content.ContentLoader;
30  import org.apache.syncope.core.persistence.jpa.entity.JPARealm;
31  import org.apache.syncope.core.spring.ApplicationContextProvider;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  import org.springframework.core.env.Environment;
35  import org.springframework.core.io.Resource;
36  import org.springframework.core.io.support.PropertiesLoaderUtils;
37  import org.springframework.dao.DataAccessException;
38  import org.springframework.jdbc.core.JdbcTemplate;
39  import org.springframework.orm.jpa.EntityManagerFactoryUtils;
40  import org.xml.sax.SAXException;
41  
42  /**
43   * Initialize Database with default content if no data is present already.
44   */
45  public class XMLContentLoader implements ContentLoader {
46  
47      protected static final Logger LOG = LoggerFactory.getLogger(XMLContentLoader.class);
48  
49      protected final Resource viewsXML;
50  
51      protected final Resource indexesXML;
52  
53      protected final Environment env;
54  
55      public XMLContentLoader(
56              final Resource viewsXML,
57              final Resource indexesXML,
58              final Environment env) {
59  
60          this.viewsXML = viewsXML;
61          this.indexesXML = indexesXML;
62          this.env = env;
63      }
64  
65      @Override
66      public int getOrder() {
67          return 400;
68      }
69  
70      @Override
71      public void load(final String domain, final DataSource datasource) {
72          LOG.debug("Loading data for domain [{}]", domain);
73  
74          // create EntityManager so OpenJPA will build the SQL schema
75          EntityManagerFactoryUtils.findEntityManagerFactory(
76                  ApplicationContextProvider.getBeanFactory(), domain).createEntityManager();
77  
78          JdbcTemplate jdbcTemplate = new JdbcTemplate(datasource);
79          boolean existingData;
80          try {
81              existingData = jdbcTemplate.queryForObject("SELECT COUNT(0) FROM " + JPARealm.TABLE, Integer.class) > 0;
82          } catch (DataAccessException e) {
83              LOG.error("[{}] Could not access table " + JPARealm.TABLE, domain, e);
84              existingData = true;
85          }
86  
87          if (existingData) {
88              LOG.info("[{}] Data found in the database, leaving untouched", domain);
89          } else {
90              LOG.info("[{}] Empty database found, loading default content", domain);
91  
92              try {
93                  createViews(domain, datasource);
94              } catch (IOException e) {
95                  LOG.error("[{}] While creating views", domain, e);
96              }
97              try {
98                  createIndexes(domain, datasource);
99              } catch (IOException e) {
100                 LOG.error("[{}] While creating indexes", domain, e);
101             }
102             try {
103                 InputStream contentXML = ApplicationContextProvider.getBeanFactory().
104                         getBean(domain + "ContentXML", InputStream.class);
105                 loadDefaultContent(domain, contentXML, datasource);
106             } catch (Exception e) {
107                 LOG.error("[{}] While loading default content", domain, e);
108             }
109         }
110     }
111 
112     protected void loadDefaultContent(
113             final String domain, final InputStream contentXML, final DataSource dataSource)
114             throws IOException, ParserConfigurationException, SAXException {
115 
116         SAXParserFactory factory = SAXParserFactory.newInstance();
117         factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
118         factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
119         try (contentXML) {
120             SAXParser parser = factory.newSAXParser();
121             parser.parse(contentXML, new ContentLoaderHandler(dataSource, ROOT_ELEMENT, true, env));
122             LOG.debug("[{}] Default content successfully loaded", domain);
123         }
124     }
125 
126     protected void createViews(final String domain, final DataSource dataSource) throws IOException {
127         LOG.debug("[{}] Creating views", domain);
128 
129         JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
130 
131         Properties views = PropertiesLoaderUtils.loadProperties(viewsXML);
132         views.stringPropertyNames().stream().sorted().forEach(idx -> {
133             LOG.debug("[{}] Creating view {}", domain, views.get(idx).toString());
134             try {
135                 jdbcTemplate.execute(views.getProperty(idx).replaceAll("\\n", " "));
136             } catch (DataAccessException e) {
137                 LOG.error("[{}] Could not create view", domain, e);
138             }
139         });
140 
141         LOG.debug("Views created");
142     }
143 
144     protected void createIndexes(final String domain, final DataSource dataSource) throws IOException {
145         LOG.debug("[{}] Creating indexes", domain);
146 
147         JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
148 
149         Properties indexes = PropertiesLoaderUtils.loadProperties(indexesXML);
150         indexes.stringPropertyNames().stream().sorted().forEach(idx -> {
151             LOG.debug("[{}] Creating index {}", domain, indexes.get(idx).toString());
152             try {
153                 jdbcTemplate.execute(indexes.getProperty(idx));
154             } catch (DataAccessException e) {
155                 LOG.error("[{}] Could not create index", domain, e);
156             }
157         });
158 
159         LOG.debug("Indexes created");
160     }
161 }