package org.jboss.windup.rules.apps.javaee.rules; import static org.joox.JOOX.$; import java.util.logging.Level; 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.phase.InitialAnalysisPhase; 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.config.projecttraversal.ProjectTraversalCache; import org.jboss.windup.reporting.model.TechnologyTagLevel; import org.jboss.windup.reporting.service.TechnologyTagService; import org.jboss.windup.rules.apps.java.model.JavaClassModel; import org.jboss.windup.rules.apps.java.service.JavaClassService; import org.jboss.windup.rules.apps.javaee.model.HibernateEntityModel; import org.jboss.windup.rules.apps.javaee.model.HibernateMappingFileModel; import org.jboss.windup.rules.apps.javaee.service.HibernateEntityService; import org.jboss.windup.rules.apps.javaee.service.HibernateMappingFileService; 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.xml.XmlUtil; import org.ocpsoft.rewrite.config.ConditionBuilder; import org.ocpsoft.rewrite.context.EvaluationContext; import org.w3c.dom.Document; import com.thinkaurelius.titan.core.attribute.Text; import com.tinkerpop.blueprints.Vertex; import com.tinkerpop.frames.FramedGraphQuery; import com.tinkerpop.gremlin.java.GremlinPipeline; import org.jboss.windup.config.metadata.RuleMetadata; /** * Discovers the hibernate.hbm.xml files. */ @RuleMetadata(phase = InitialAnalysisPhase.class, perform = "Discover hibernate.hbm.xml files") public class DiscoverHibernateMappingRuleProvider extends IteratingRuleProvider<DoctypeMetaModel> { private static final Logger LOG = Logger.getLogger(DiscoverHibernateMappingRuleProvider.class.getSimpleName()); private static final String TECH_TAG = "Hibernate Mapping"; private static final TechnologyTagLevel TECH_TAG_LEVEL = TechnologyTagLevel.IMPORTANT; private static final String REGEX_HIBERNATE = "(?i).*hibernate.mapping.*"; @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) { JavaClassService javaClassService = new JavaClassService(event.getGraphContext()); HibernateMappingFileService hibernateMappingFileService = new HibernateMappingFileService( event.getGraphContext()); HibernateEntityService hibernateEntityService = new HibernateEntityService(event.getGraphContext()); XmlFileService xmlFileService = new XmlFileService(event.getGraphContext()); TechnologyTagService technologyTagService = new TechnologyTagService(event.getGraphContext()); 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()) { // create a facet, and then identify the XML. HibernateMappingFileModel hibernateMapping = hibernateMappingFileService.addTypeToModel(xml); Document doc = xmlFileService.loadDocumentQuiet(event, context, hibernateMapping); if (!XmlUtil.xpathExists(doc, "/hibernate-mapping", null)) { LOG.log(Level.INFO, "Docment does not contain Hibernate Mapping."); continue; } String clzPkg = $(doc).xpath("/hibernate-mapping").attr("package"); String clzName = $(doc).xpath("/hibernate-mapping/class").attr("name"); String tableName = $(doc).xpath("/hibernate-mapping/class").attr("table"); String schemaName = $(doc).xpath("/hibernate-mapping/class").attr("schema"); String catalogName = $(doc).xpath("/hibernate-mapping/class").attr("catalog"); if (StringUtils.isBlank(clzName)) { LOG.log(Level.FINE, "Docment does not contain class name. Skipping."); continue; } technologyTagService.addTagToFileModel(xml, TECH_TAG, TECH_TAG_LEVEL); // prepend with package name. if (StringUtils.isNotBlank(clzPkg) && !StringUtils.startsWith(clzName, clzPkg)) { clzName = clzPkg + "." + clzName; } // get a reference to the Java class. JavaClassModel clz = javaClassService.getOrCreatePhantom(clzName); // create the hibernate facet. HibernateEntityModel hibernateEntity = hibernateEntityService.create(); hibernateEntity.setSpecificationVersion(versionInformation); hibernateEntity.setApplications(ProjectTraversalCache.getApplicationsForProject(event.getGraphContext(), xml.getProjectModel())); hibernateEntity.setJavaClass(clz); hibernateEntity.setTableName(tableName); hibernateEntity.setSchemaName(schemaName); hibernateEntity.setCatalogName(catalogName); // map the entity back to the XML mapping. hibernateMapping.addHibernateEntity(hibernateEntity); if (StringUtils.isNotBlank(versionInformation)) { hibernateEntity.setSpecificationVersion(versionInformation); hibernateMapping.setSpecificationVersion(versionInformation); } } } 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; } }