package org.jboss.windup.rules.apps.javaee.rules; import static org.joox.JOOX.$; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.jboss.windup.config.GraphRewrite; import org.jboss.windup.config.metadata.RuleMetadata; import org.jboss.windup.config.phase.InitialAnalysisPhase; import org.jboss.windup.config.projecttraversal.ProjectTraversalCache; import org.jboss.windup.config.query.Query; import org.jboss.windup.config.query.QueryGremlinCriterion; import org.jboss.windup.config.ruleprovider.IteratingRuleProvider; import org.jboss.windup.graph.GraphContext; import org.jboss.windup.graph.model.ProjectModel; import org.jboss.windup.graph.service.GraphService; import org.jboss.windup.reporting.model.TechnologyTagLevel; import org.jboss.windup.reporting.service.TechnologyTagService; import org.jboss.windup.rules.apps.javaee.model.DataSourceModel; import org.jboss.windup.rules.apps.javaee.model.HibernateConfigurationFileModel; import org.jboss.windup.rules.apps.javaee.model.HibernateSessionFactoryModel; import org.jboss.windup.rules.apps.javaee.service.DataSourceService; import org.jboss.windup.rules.apps.javaee.service.HibernateConfigurationFileService; import org.jboss.windup.rules.apps.javaee.util.HibernateDialectDataSourceTypeResolver; import org.jboss.windup.rules.apps.xml.model.DoctypeMetaModel; import org.jboss.windup.rules.apps.xml.model.XmlFileModel; import org.jboss.windup.rules.apps.xml.service.XmlFileService; import org.jboss.windup.util.Logging; import org.ocpsoft.rewrite.config.ConditionBuilder; import org.ocpsoft.rewrite.context.EvaluationContext; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.thinkaurelius.titan.core.attribute.Text; import com.tinkerpop.blueprints.Vertex; import com.tinkerpop.frames.FramedGraphQuery; import com.tinkerpop.gremlin.java.GremlinPipeline; /** * Discovers Hibernate Configuration Files (eg, hibernate.cfg.xml), extracts their metadata, and places this metadata into the graph. * * @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a> * */ @RuleMetadata(phase = InitialAnalysisPhase.class, perform = "Discover hibernate.cfg.xml files") public class DiscoverHibernateConfigurationRuleProvider extends IteratingRuleProvider<DoctypeMetaModel> { private static final Logger LOG = Logging.get(DiscoverHibernateConfigurationRuleProvider.class); private static final String TECH_TAG = "Hibernate Cfg"; private static final TechnologyTagLevel TECH_TAG_LEVEL = TechnologyTagLevel.IMPORTANT; private static final String REGEX_HIBERNATE = "(?i).*hibernate.configuration.*"; @Override public ConditionBuilder when() { QueryGremlinCriterion doctypeSearchCriterion = new QueryGremlinCriterion() { @Override public void query(GraphRewrite event, GremlinPipeline<Vertex, Vertex> pipeline) { pipeline.has(DoctypeMetaModel.PROPERTY_PUBLIC_ID, Text.REGEX, REGEX_HIBERNATE); FramedGraphQuery systemIDQuery = event.getGraphContext().getQuery().type(DoctypeMetaModel.class) .has(DoctypeMetaModel.PROPERTY_SYSTEM_ID, Text.REGEX, REGEX_HIBERNATE); GremlinPipeline<Vertex, Vertex> systemIdPipeline = new GremlinPipeline<>(systemIDQuery.vertices()); pipeline.add(systemIdPipeline); pipeline.dedup(); } }; return Query.fromType(DoctypeMetaModel.class).piped(doctypeSearchCriterion); } @Override public void perform(GraphRewrite event, EvaluationContext context, DoctypeMetaModel payload) { String publicId = payload.getPublicId(); String systemId = payload.getSystemId(); // extract the version information from the public / system ID. String versionInformation = extractVersion(publicId, systemId); for (XmlFileModel xml : payload.getXmlResources()) { createHibernateConfigurationModel(event, context, xml, versionInformation); } } private void createHibernateConfigurationModel(GraphRewrite event, EvaluationContext context, XmlFileModel xmlFileModel, String versionInformation) { GraphContext graphContext = event.getGraphContext(); DataSourceService dataSourceService = new DataSourceService(graphContext); HibernateConfigurationFileService hibernateConfigurationFileService = new HibernateConfigurationFileService(graphContext); GraphService<HibernateSessionFactoryModel> hibernateSessionFactoryService = new GraphService<>(graphContext, HibernateSessionFactoryModel.class); TechnologyTagService technologyTagService = new TechnologyTagService(graphContext); // check the root XML node. HibernateConfigurationFileModel hibernateConfigurationModel = hibernateConfigurationFileService.addTypeToModel(xmlFileModel); technologyTagService.addTagToFileModel(hibernateConfigurationModel, TECH_TAG, TECH_TAG_LEVEL); if (StringUtils.isNotBlank(versionInformation)) { hibernateConfigurationModel.setSpecificationVersion(versionInformation); } Set<ProjectModel> applications = ProjectTraversalCache.getApplicationsForProject(event.getGraphContext(), xmlFileModel.getProjectModel()); Document doc = new XmlFileService(graphContext).loadDocumentQuiet(event, context, xmlFileModel); for (Element element : $(doc).find("session-factory").get()) { HibernateSessionFactoryModel sessionFactoryModel = hibernateSessionFactoryService.create(); hibernateConfigurationModel.addHibernateSessionFactory(sessionFactoryModel); Map<String, String> sessionFactoryProperties = new HashMap<>(); for (Element propElement : $(element).find("property")) { String propKey = $(propElement).attr("name"); String propValue = $(propElement).text().trim(); sessionFactoryProperties.put(propKey, propValue); } sessionFactoryModel.setSessionFactoryProperties(sessionFactoryProperties); // create the datasource references. if (sessionFactoryProperties.containsKey("hibernate.connection.datasource")) { final String dataSourceJndiName = sessionFactoryProperties.get("hibernate.connection.datasource"); String dataSourceName = dataSourceJndiName; if (StringUtils.contains(dataSourceName, "/")) { dataSourceName = StringUtils.substringAfterLast(dataSourceName, "/"); } DataSourceModel dataSource = dataSourceService.createUnique(applications, dataSourceName, dataSourceJndiName); if (sessionFactoryProperties.containsKey("hibernate.dialect")) { String dialect = sessionFactoryProperties.get("hibernate.dialect"); String resolvedType = HibernateDialectDataSourceTypeResolver.resolveDataSourceTypeFromDialect(dialect); if(StringUtils.isNotBlank(resolvedType)) { dataSource.setDatabaseTypeName(resolvedType); } } } } } private String extractVersion(String publicId, String systemId) { Pattern pattern = Pattern.compile("[0-9][0-9a-zA-Z.-]+"); if (StringUtils.isNotBlank(publicId)) { Matcher matcher = pattern.matcher(publicId); if (matcher.find()) { return matcher.group(); } } if (StringUtils.isNotBlank(systemId)) { Matcher matcher = pattern.matcher(systemId); if (matcher.find()) { String match = matcher.group(); // for system ID, make sure to remove the ".dtd" that could come in. return StringUtils.removeEnd(match, ".dtd"); } } return null; } }