From 02311ae5dd260909865298ca36b85c6085f5b503 Mon Sep 17 00:00:00 2001 From: Josef Rokos Date: Tue, 6 Jan 2015 09:08:36 +0100 Subject: [PATCH] =?UTF-8?q?Rozd=C4=9Blan=C3=A9=20fulltextov=C3=A9=20vyhled?= =?UTF-8?q?=C3=A1v=C3=A1n=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 20 ++- .../info/bukova/isspst/AppInitListener.java | 8 + .../java/info/bukova/isspst/Constants.java | 4 + .../bukova/isspst/RequirementUrlResolver.java | 2 +- .../info/bukova/isspst/data/AddressEmb.java | 7 + .../info/bukova/isspst/data/BaseData.java | 6 + .../info/bukova/isspst/data/FileMetainfo.java | 71 +++++++++ .../java/info/bukova/isspst/data/Order.java | 9 ++ .../info/bukova/isspst/data/OrderItem.java | 9 ++ .../info/bukova/isspst/data/Requirement.java | 5 + .../bukova/isspst/data/RequirementBase.java | 6 + .../bukova/isspst/data/RequirementItem.java | 10 ++ .../info/bukova/isspst/data/TripBill.java | 15 ++ .../bukova/isspst/data/TripRequirement.java | 21 +++ .../java/info/bukova/isspst/data/User.java | 7 + .../isspst/services/FullTextService.java | 11 ++ .../isspst/services/FullTextServiceImpl.java | 143 ++++++++++++++++++ .../bukova/isspst/sort/ReflectionTools.java | 21 +++ .../ui/search/AbstractResultTransformer.java | 37 +++++ .../ui/search/CommonResultTransformer.java | 12 ++ .../ui/search/OrderResultTransformer.java | 14 ++ .../search/RequirementResultTransformer.java | 14 ++ .../isspst/ui/search/ResultTransformer.java | 10 ++ .../bukova/isspst/ui/search/SearchForm.java | 58 +++++++ .../ui/search/SearchListTransformer.java | 41 +++++ .../bukova/isspst/ui/search/SearchResult.java | 73 +++++++++ .../isspst/ui/search/TransformerFactory.java | 27 ++++ .../isspst/ui/search/TripBillTransformer.java | 14 ++ .../ui/search/TripRequirementTransformer.java | 14 ++ src/main/resources/hibernate.cfg.xml | 1 + .../webapp/WEB-INF/spring/root-context.xml | 7 +- src/main/webapp/search/searchForm.zul | 49 ++++++ 32 files changed, 736 insertions(+), 10 deletions(-) create mode 100644 src/main/java/info/bukova/isspst/data/FileMetainfo.java create mode 100644 src/main/java/info/bukova/isspst/services/FullTextService.java create mode 100644 src/main/java/info/bukova/isspst/services/FullTextServiceImpl.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/AbstractResultTransformer.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/CommonResultTransformer.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/OrderResultTransformer.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/RequirementResultTransformer.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/ResultTransformer.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/SearchForm.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/SearchListTransformer.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/SearchResult.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/TransformerFactory.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/TripBillTransformer.java create mode 100644 src/main/java/info/bukova/isspst/ui/search/TripRequirementTransformer.java create mode 100644 src/main/webapp/search/searchForm.zul diff --git a/pom.xml b/pom.xml index 49b8dfcb..3a78e29c 100644 --- a/pom.xml +++ b/pom.xml @@ -215,16 +215,20 @@ - org.hibernate - hibernate-core - 4.2.8.Final + org.hibernate + hibernate-core + 4.2.8.Final - org.hibernate - hibernate-validator - 4.3.0.Final - - + org.hibernate + hibernate-validator + 4.3.0.Final + + + org.hibernate + hibernate-search + 4.4.6.Final + diff --git a/src/main/java/info/bukova/isspst/AppInitListener.java b/src/main/java/info/bukova/isspst/AppInitListener.java index 1f9a3e73..b8faa1ac 100644 --- a/src/main/java/info/bukova/isspst/AppInitListener.java +++ b/src/main/java/info/bukova/isspst/AppInitListener.java @@ -11,6 +11,7 @@ import info.bukova.isspst.data.User; import info.bukova.isspst.reporting.Report; import info.bukova.isspst.reporting.ReportMapping; import info.bukova.isspst.reporting.ReportType; +import info.bukova.isspst.services.FullTextService; import info.bukova.isspst.services.munits.MUnitService; import info.bukova.isspst.services.numberseries.NumberSeriesService; import info.bukova.isspst.services.requirement.RequirementTypeService; @@ -40,6 +41,7 @@ public class AppInitListener implements ServletContextListener { private NumberSeriesService nsService; private RequirementTypeService reqTypeService; private GlobalSettingsService gSettingsService; + private FullTextService ftService; @Override public void contextDestroyed(ServletContextEvent arg0) { @@ -59,6 +61,7 @@ public class AppInitListener implements ServletContextListener { nsService =ctx.getBean(NumberSeriesService.class); gSettingsService = ctx.getBean(GlobalSettingsService.class); reqTypeService = ctx.getBean(RequirementTypeService.class); + ftService = ctx.getBean(FullTextService.class); userService.grantAdmin(); checkMUnits(); @@ -69,11 +72,16 @@ public class AppInitListener implements ServletContextListener { this.checkNumberSeries(); checkReqTypes(); this.checkGlobalSettings(); + buildFulltext(); userService.removeAccess(); loadModuleReports(); } + private void buildFulltext() { + ftService.reindex(); + } + private void checkMUnits() { List mUnits = mUnitsService.getAll(); diff --git a/src/main/java/info/bukova/isspst/Constants.java b/src/main/java/info/bukova/isspst/Constants.java index 875514c2..8630c523 100644 --- a/src/main/java/info/bukova/isspst/Constants.java +++ b/src/main/java/info/bukova/isspst/Constants.java @@ -4,11 +4,13 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import info.bukova.isspst.data.Order; import info.bukova.isspst.data.Permission; import info.bukova.isspst.data.PermissionType; import info.bukova.isspst.data.Requirement; import info.bukova.isspst.data.RequirementType; import info.bukova.isspst.data.Role; +import info.bukova.isspst.data.TripBill; import info.bukova.isspst.data.TripRequirement; import info.bukova.isspst.reporting.Report; import info.bukova.isspst.reporting.ReportMapping; @@ -141,5 +143,7 @@ public class Constants { public final static Map, String> URL_MAP = Collections.unmodifiableMap(new HashMap, String>() {{ put(Requirement.class, "/main/orders/"); put(TripRequirement.class, "/main/trips/requirements/"); + put(Order.class, "/main/orders/created/"); + put(TripBill.class, "/main/trips/bill/"); }} ); } diff --git a/src/main/java/info/bukova/isspst/RequirementUrlResolver.java b/src/main/java/info/bukova/isspst/RequirementUrlResolver.java index 117fe81b..11a6b634 100644 --- a/src/main/java/info/bukova/isspst/RequirementUrlResolver.java +++ b/src/main/java/info/bukova/isspst/RequirementUrlResolver.java @@ -29,7 +29,7 @@ public class RequirementUrlResolver implements EntityUrlResolver { Requirement req = (Requirement)entity; - if (req.getKind() == Constants.REQ_TYPE_MATERIAL) { + if (req.getKind() != null && req.getKind() == Constants.REQ_TYPE_MATERIAL) { return defaultUrl + Constants.URL_MAP.get(req.getClass()) + "material/?select=" + String.valueOf(req.getId()); } else { return defaultUrl + Constants.URL_MAP.get(req.getClass()) + "services/?select=" + String.valueOf(req.getId()); diff --git a/src/main/java/info/bukova/isspst/data/AddressEmb.java b/src/main/java/info/bukova/isspst/data/AddressEmb.java index 402004f9..723c0384 100644 --- a/src/main/java/info/bukova/isspst/data/AddressEmb.java +++ b/src/main/java/info/bukova/isspst/data/AddressEmb.java @@ -7,11 +7,18 @@ import java.util.List; import javax.persistence.Embeddable; +import org.hibernate.search.annotations.Analyze; +import org.hibernate.search.annotations.Field; +import org.hibernate.search.annotations.Index; +import org.hibernate.search.annotations.Indexed; + @Embeddable +@Indexed public class AddressEmb { private int id; + @Field(index = Index.YES, analyze = Analyze.YES) private String company; private String department; private String contactName; diff --git a/src/main/java/info/bukova/isspst/data/BaseData.java b/src/main/java/info/bukova/isspst/data/BaseData.java index b3ce062f..8977fba5 100644 --- a/src/main/java/info/bukova/isspst/data/BaseData.java +++ b/src/main/java/info/bukova/isspst/data/BaseData.java @@ -11,7 +11,11 @@ import javax.persistence.ManyToOne; import javax.persistence.MappedSuperclass; import javax.persistence.Transient; +import org.hibernate.search.annotations.Indexed; +import org.hibernate.search.annotations.IndexedEmbedded; + @MappedSuperclass +@Indexed public abstract class BaseData implements OwnedDataModel { @Id @@ -24,9 +28,11 @@ public abstract class BaseData implements OwnedDataModel { private Date modified; @ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name="OWNED_BY_ID") + @IndexedEmbedded private User ownedBy; @ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name="MODIFIED_BY_ID") + @IndexedEmbedded private User modifiedBy; @Transient private boolean valid; diff --git a/src/main/java/info/bukova/isspst/data/FileMetainfo.java b/src/main/java/info/bukova/isspst/data/FileMetainfo.java new file mode 100644 index 00000000..9a6ba906 --- /dev/null +++ b/src/main/java/info/bukova/isspst/data/FileMetainfo.java @@ -0,0 +1,71 @@ +package info.bukova.isspst.data; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +import org.hibernate.annotations.Type; +import org.hibernate.search.annotations.Analyze; +import org.hibernate.search.annotations.Field; +import org.hibernate.search.annotations.Index; +import org.hibernate.search.annotations.Indexed; + +@Entity +@Table(name = "FILE_METAINFO") +@Indexed +public class FileMetainfo extends BaseData { + + @Column(name = "FILE_NAME") + private String fileName; + @Column(name = "PATH_IN_FILESYSTEM") + private String pathInFilesystem; + @Column(name = "MODULE_ID") + private String moduleId; + @Column(name = "RECORD_ID") + private int recordId; + @Column(name = "CONTENT") + @Type(type = "text") + @Field(index = Index.YES, analyze = Analyze.YES) + private String content; + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getPathInFilesystem() { + return pathInFilesystem; + } + + public void setPathInFilesystem(String pathInFilesystem) { + this.pathInFilesystem = pathInFilesystem; + } + + public String getModuleId() { + return moduleId; + } + + public void setModuleId(String moduleId) { + this.moduleId = moduleId; + } + + public int getRecordId() { + return recordId; + } + + public void setRecordId(int recordId) { + this.recordId = recordId; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + +} diff --git a/src/main/java/info/bukova/isspst/data/Order.java b/src/main/java/info/bukova/isspst/data/Order.java index 79348edb..6f36acb1 100644 --- a/src/main/java/info/bukova/isspst/data/Order.java +++ b/src/main/java/info/bukova/isspst/data/Order.java @@ -16,9 +16,15 @@ import javax.persistence.Table; import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollectionOption; +import org.hibernate.search.annotations.Analyze; +import org.hibernate.search.annotations.Field; +import org.hibernate.search.annotations.Index; +import org.hibernate.search.annotations.Indexed; +import org.hibernate.search.annotations.IndexedEmbedded; @Entity @Table(name = "ORDERS") +@Indexed public class Order extends BaseData implements Cloneable { @@ -45,6 +51,7 @@ public class Order extends BaseData implements Cloneable @AttributeOverride(name = "street", column = @Column(name = "SUPPLIER_STREET")), @AttributeOverride(name = "web", column = @Column(name = "SUPPLIER_WEB")), @AttributeOverride(name = "zipCode", column = @Column(name = "SUPPLIER_ZIP_CODE")) }) + @IndexedEmbedded private AddressEmb suplier; @Embedded @@ -95,10 +102,12 @@ public class Order extends BaseData implements Cloneable private String deliveryType; @Column(name = "DESCRIPTION") + @Field(index = Index.YES, analyze = Analyze.YES) private String description; @OneToMany(cascade = CascadeType.ALL, mappedBy = "order", orphanRemoval = true) @LazyCollection(LazyCollectionOption.TRUE) + @IndexedEmbedded private List items; @Column(name = "TOTAL", precision = 15, scale = 4) diff --git a/src/main/java/info/bukova/isspst/data/OrderItem.java b/src/main/java/info/bukova/isspst/data/OrderItem.java index 16f26a24..c9c01413 100644 --- a/src/main/java/info/bukova/isspst/data/OrderItem.java +++ b/src/main/java/info/bukova/isspst/data/OrderItem.java @@ -12,8 +12,14 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; +import org.hibernate.search.annotations.Analyze; +import org.hibernate.search.annotations.Field; +import org.hibernate.search.annotations.Index; +import org.hibernate.search.annotations.Indexed; + @Entity @Table(name = "ORDER_ITEM") +@Indexed public class OrderItem { @@ -26,9 +32,11 @@ public class OrderItem private String code; @Column(name = "NAME") + @Field(index = Index.YES, analyze = Analyze.YES) private String name; @Column(name = "TEXTITEM") + @Field(index = Index.YES, analyze = Analyze.YES) private String textItem; @Column(name = "QUANTITY", precision = 15, scale = 4) @@ -44,6 +52,7 @@ public class OrderItem private BigDecimal total; @Column(name = "DESCRIPTION") + @Field(index = Index.YES, analyze = Analyze.YES) private String description; @ManyToOne(fetch = FetchType.EAGER) diff --git a/src/main/java/info/bukova/isspst/data/Requirement.java b/src/main/java/info/bukova/isspst/data/Requirement.java index 084670e2..1aa97a38 100644 --- a/src/main/java/info/bukova/isspst/data/Requirement.java +++ b/src/main/java/info/bukova/isspst/data/Requirement.java @@ -12,11 +12,16 @@ import javax.persistence.FetchType; import javax.persistence.OneToMany; import javax.persistence.Table; +import org.hibernate.search.annotations.Indexed; +import org.hibernate.search.annotations.IndexedEmbedded; + @Entity @Table(name = "REQUIREMENT") +@Indexed public class Requirement extends RequirementBase { @OneToMany(fetch = FetchType.LAZY, mappedBy = "requirement", cascade = CascadeType.ALL, orphanRemoval = true) + @IndexedEmbedded private List items; @Column(name = "DELIVERYDATE") diff --git a/src/main/java/info/bukova/isspst/data/RequirementBase.java b/src/main/java/info/bukova/isspst/data/RequirementBase.java index a9a549a3..2a3a79db 100644 --- a/src/main/java/info/bukova/isspst/data/RequirementBase.java +++ b/src/main/java/info/bukova/isspst/data/RequirementBase.java @@ -17,8 +17,13 @@ import javax.persistence.OrderBy; import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollectionOption; +import org.hibernate.search.annotations.Analyze; +import org.hibernate.search.annotations.Field; +import org.hibernate.search.annotations.Index; +import org.hibernate.search.annotations.Indexed; @MappedSuperclass +@Indexed public class RequirementBase extends BaseData implements FilterableRequirement { @ManyToOne(fetch = FetchType.LAZY) @@ -33,6 +38,7 @@ public class RequirementBase extends BaseData implements FilterableRequirement { @Column(name = "REQ_DATE") private Date reqDate; @Column(name = "DESCRIPTION") + @Field(index = Index.YES, analyze = Analyze.YES) private String description; @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "CENTRE_ID") diff --git a/src/main/java/info/bukova/isspst/data/RequirementItem.java b/src/main/java/info/bukova/isspst/data/RequirementItem.java index 20c7e95a..da75aff1 100644 --- a/src/main/java/info/bukova/isspst/data/RequirementItem.java +++ b/src/main/java/info/bukova/isspst/data/RequirementItem.java @@ -12,8 +12,15 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; +import org.hibernate.search.annotations.Analyze; +import org.hibernate.search.annotations.Field; +import org.hibernate.search.annotations.Index; +import org.hibernate.search.annotations.Indexed; +import org.hibernate.search.annotations.IndexedEmbedded; + @Entity @Table(name = "REQUIREMENT_ITEMS") +@Indexed public class RequirementItem { @Id @@ -33,9 +40,11 @@ public class RequirementItem private String code; @Column(name = "NAME") + @Field(index = Index.YES, analyze = Analyze.YES) private String name; @Column(name = "TEXTITEM") + @Field(index = Index.YES, analyze = Analyze.YES) private String textItem; @Column(name = "QUANTITY", precision=15, scale=4) @@ -51,6 +60,7 @@ public class RequirementItem private BigDecimal total; @Column(name = "DESCRIPTION") + @Field(index = Index.YES, analyze = Analyze.YES) private String description; @Column(name = "DELIVERED") diff --git a/src/main/java/info/bukova/isspst/data/TripBill.java b/src/main/java/info/bukova/isspst/data/TripBill.java index 7029654f..b5dfae2e 100644 --- a/src/main/java/info/bukova/isspst/data/TripBill.java +++ b/src/main/java/info/bukova/isspst/data/TripBill.java @@ -16,9 +16,12 @@ import javax.persistence.Table; import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollectionOption; +import org.hibernate.search.annotations.Indexed; +import org.hibernate.search.annotations.IndexedEmbedded; @Entity @Table(name = "TRIP_BILL") +@Indexed public class TripBill extends BaseData { @OneToOne(fetch = FetchType.EAGER) @@ -44,6 +47,10 @@ public class TripBill extends BaseData { private BigDecimal downPayment; @Column(name = "TOTAL", precision = 15, scale = 4) private BigDecimal total; + @OneToMany + @LazyCollection(LazyCollectionOption.TRUE) + @IndexedEmbedded + private List attachedFiles; public TripBill() { billItems = new ArrayList(); @@ -121,4 +128,12 @@ public class TripBill extends BaseData { this.total = total; } + public List getAttachedFiles() { + return attachedFiles; + } + + public void setAttachedFiles(List attachedFiles) { + this.attachedFiles = attachedFiles; + } + } diff --git a/src/main/java/info/bukova/isspst/data/TripRequirement.java b/src/main/java/info/bukova/isspst/data/TripRequirement.java index e180571f..7048fe6b 100644 --- a/src/main/java/info/bukova/isspst/data/TripRequirement.java +++ b/src/main/java/info/bukova/isspst/data/TripRequirement.java @@ -11,18 +11,27 @@ import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; +import javax.persistence.OneToMany; import javax.persistence.Table; import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollectionOption; +import org.hibernate.search.annotations.Analyze; +import org.hibernate.search.annotations.Field; +import org.hibernate.search.annotations.Index; +import org.hibernate.search.annotations.Indexed; +import org.hibernate.search.annotations.IndexedEmbedded; @Entity @Table(name = "TRIPREQUIREMENT") +@Indexed public class TripRequirement extends RequirementBase { @Column(name = "TRIP_FROM") + @Field(index = Index.YES, analyze = Analyze.YES) private String from; @Column(name = "TRIP_TO") + @Field(index = Index.YES, analyze = Analyze.YES) private String to; @Column(name = "TRIP_DATE") private Date tripDate; @@ -40,6 +49,10 @@ public class TripRequirement extends RequirementBase { private Boolean requireDownPayment; @Column(name = "DOWN_PAYMENT", precision = 15, scale = 4) private BigDecimal downPayment; + @OneToMany + @LazyCollection(LazyCollectionOption.TRUE) + @IndexedEmbedded + private List attachedFiles; public TripRequirement() { this.setOwnedBy(new User()); @@ -118,4 +131,12 @@ public class TripRequirement extends RequirementBase { this.downPayment = downPayment; } + public List getAttachedFiles() { + return attachedFiles; + } + + public void setAttachedFiles(List attachedFiles) { + this.attachedFiles = attachedFiles; + } + } diff --git a/src/main/java/info/bukova/isspst/data/User.java b/src/main/java/info/bukova/isspst/data/User.java index 65c75770..144a2b7f 100644 --- a/src/main/java/info/bukova/isspst/data/User.java +++ b/src/main/java/info/bukova/isspst/data/User.java @@ -14,10 +14,15 @@ import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; +import org.hibernate.search.annotations.Analyze; +import org.hibernate.search.annotations.Field; +import org.hibernate.search.annotations.Index; +import org.hibernate.search.annotations.Indexed; import org.springframework.security.core.userdetails.UserDetails; @Entity @Table(name="USER") +@Indexed public class User extends Member implements UserDetails, DataModel { /** @@ -32,8 +37,10 @@ public class User extends Member implements UserDetails, DataModel { @Column(name="ENABLED") private boolean enabled; @Column(name="FIRST_NAME") + @Field(index = Index.YES, analyze = Analyze.YES) private String firstName; @Column(name="LAST_NAME") + @Field(index = Index.YES, analyze = Analyze.YES) private String lastName; @Column(name="PERSONAL_NUMBER") private String personalNumber; diff --git a/src/main/java/info/bukova/isspst/services/FullTextService.java b/src/main/java/info/bukova/isspst/services/FullTextService.java new file mode 100644 index 00000000..2336c0ab --- /dev/null +++ b/src/main/java/info/bukova/isspst/services/FullTextService.java @@ -0,0 +1,11 @@ +package info.bukova.isspst.services; + +import java.util.List; + +public interface FullTextService { + + public void reindex(); + public List search(Class entityClass, String[] fields, String word); + public List globalSearch(String word); + +} diff --git a/src/main/java/info/bukova/isspst/services/FullTextServiceImpl.java b/src/main/java/info/bukova/isspst/services/FullTextServiceImpl.java new file mode 100644 index 00000000..12018c4b --- /dev/null +++ b/src/main/java/info/bukova/isspst/services/FullTextServiceImpl.java @@ -0,0 +1,143 @@ +package info.bukova.isspst.services; + +import info.bukova.isspst.dao.QueryDao; +import info.bukova.isspst.data.BaseData; +import info.bukova.isspst.data.User; +import info.bukova.isspst.sort.ReflectionTools; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.lucene.search.Query; +import org.hibernate.Hibernate; +import org.hibernate.search.FullTextSession; +import org.hibernate.search.Search; +import org.hibernate.search.annotations.IndexedEmbedded; +import org.hibernate.search.query.dsl.QueryBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +public class FullTextServiceImpl implements FullTextService { + + @Autowired + private QueryDao queryDao; + private List> classesForSearch; + private Map, String[]> fields; + private List> nestedClasses; + + public FullTextServiceImpl() { + nestedClasses = new ArrayList>(); + nestedClasses.add(User.class); + nestedClasses.add(BaseData.class); + } + + @Override + @Transactional + public void reindex() { + Logger logger = LoggerFactory.getLogger(FullTextServiceImpl.class); + logger.info("Indexing database for fulltext search"); + FullTextSession ftSession = Search.getFullTextSession(queryDao.getSession()); + try { + ftSession.createIndexer().startAndWait(); + } catch (InterruptedException e) { + logger.error("Cannot index database"); + } + } + + @Override + @Transactional + public List search(Class entityClass, String[] fields, String word) { + FullTextSession session = Search.getFullTextSession(queryDao.getSession()); + QueryBuilder qb = session.getSearchFactory().buildQueryBuilder().forEntity(entityClass).get(); + + Query luceneQuery = qb.keyword().onFields(fields).matching(word).createQuery(); + org.hibernate.Query hiberQuery = session.createFullTextQuery(luceneQuery, entityClass); + + return hiberQuery.list(); + } + + @Override + @Transactional + public List globalSearch(String word) { + List result = new ArrayList(); + + for (Class clazz : classesForSearch()) { + result.addAll(search(clazz, fields.get(clazz), word)); + } + + for (Object o : result) { + BaseData data = (BaseData) o; + Hibernate.initialize(data.getModifiedBy()); + Hibernate.initialize(data.getOwnedBy()); + } + + return result; + } + + private List> classesForSearch() { + if (classesForSearch != null) { + return classesForSearch; + } + + classesForSearch = new ArrayList>(); + fields = new HashMap, String[]>(); + FullTextSession session = Search.getFullTextSession(queryDao.getSession()); + + for (Class clazz : session.getSearchFactory().getIndexedTypes()) { + if (nestedClasses.contains(clazz)) { + continue; + } + + classesForSearch.add(clazz); + fields.put(clazz, fields(clazz, "")); + } + + return classesForSearch; + } + + private String[] fields(Class clazz, String prefix) { + List res = new ArrayList(); + + for (Field field : ReflectionTools.getFields(clazz)) { + for (Annotation a : field.getDeclaredAnnotations()) { + if (a instanceof org.hibernate.search.annotations.Field) { + res.add(prefix + field.getName()); + } + + if (a instanceof IndexedEmbedded) { + Class fieldClass; + + fieldClass = field.getType(); + if (fieldClass.isAssignableFrom(List.class)) { + ParameterizedType type = (ParameterizedType) field.getGenericType(); + Type[] types = type.getActualTypeArguments(); + if (types.length == 1) { + fieldClass = (Class)types[0]; + } + } + + classesForSearch.remove(fieldClass); + fields.remove(fieldClass); + nestedClasses.add(fieldClass); + + String nestedPrefix = prefix + field.getName() + "."; + res.addAll(Arrays.asList(fields(fieldClass, nestedPrefix))); + } + } + } + + String resArray[] = new String[res.size()]; + resArray = res.toArray(resArray); + return resArray; + } + +} diff --git a/src/main/java/info/bukova/isspst/sort/ReflectionTools.java b/src/main/java/info/bukova/isspst/sort/ReflectionTools.java index ed363745..379d6fc6 100644 --- a/src/main/java/info/bukova/isspst/sort/ReflectionTools.java +++ b/src/main/java/info/bukova/isspst/sort/ReflectionTools.java @@ -4,8 +4,10 @@ import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class ReflectionTools { @@ -78,4 +80,23 @@ public class ReflectionTools { return getEntityFields(entity.getClass()); } + + public static List getFields(Object entity) { + if (entity == null) { + return null; + } + + return getFields(entity.getClass()); + } + + public static List getFields(Class clazz) { + List ret = new ArrayList(); + + ret.addAll(Arrays.asList(clazz.getDeclaredFields())); + if (!clazz.getSuperclass().equals(Object.class)) { + ret.addAll(getFields(clazz.getSuperclass())); + } + + return ret; + } } diff --git a/src/main/java/info/bukova/isspst/ui/search/AbstractResultTransformer.java b/src/main/java/info/bukova/isspst/ui/search/AbstractResultTransformer.java new file mode 100644 index 00000000..e2b5f8f3 --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/AbstractResultTransformer.java @@ -0,0 +1,37 @@ +package info.bukova.isspst.ui.search; + +import info.bukova.isspst.EntityUrlResolver; +import info.bukova.isspst.data.BaseData; + +public abstract class AbstractResultTransformer implements ResultTransformer { + + protected EntityUrlResolver urlResolver; + + @Override + public SearchResult transformObject(Object object) { + BaseData data = (BaseData)object; + SearchResult result = new SearchResult(); + + result.setCreated(data.getCreated()); + result.setModified(data.getModified()); + result.setOwnedBy(data.getOwnedBy()); + result.setModifiedBy(data.getModifiedBy()); + + if (urlResolver != null) { + result.setUrl(urlResolver.entityUrl(data)); + } + + + transform(object, result); + + return result; + } + + protected abstract void transform(Object object, SearchResult result); + + @Override + public void setUrlResolver(EntityUrlResolver resolver) { + this.urlResolver = resolver; + } + +} diff --git a/src/main/java/info/bukova/isspst/ui/search/CommonResultTransformer.java b/src/main/java/info/bukova/isspst/ui/search/CommonResultTransformer.java new file mode 100644 index 00000000..d479a0e6 --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/CommonResultTransformer.java @@ -0,0 +1,12 @@ +package info.bukova.isspst.ui.search; + + +public class CommonResultTransformer extends AbstractResultTransformer implements ResultTransformer { + + @Override + protected void transform(Object object, SearchResult result) { + result.setRecordName("Neznámá entita"); + result.setDescription(object.toString()); + } + +} diff --git a/src/main/java/info/bukova/isspst/ui/search/OrderResultTransformer.java b/src/main/java/info/bukova/isspst/ui/search/OrderResultTransformer.java new file mode 100644 index 00000000..c2d2cebf --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/OrderResultTransformer.java @@ -0,0 +1,14 @@ +package info.bukova.isspst.ui.search; + +import info.bukova.isspst.data.Order; + +public class OrderResultTransformer extends AbstractResultTransformer implements ResultTransformer { + + @Override + protected void transform(Object object, SearchResult result) { + Order order = (Order)object; + result.setRecordName("Objednávka: " + order.getNumser()); + result.setDescription(order.getDescription() + ", dodavatel: " + order.getSuplier().getCompany()); + } + +} diff --git a/src/main/java/info/bukova/isspst/ui/search/RequirementResultTransformer.java b/src/main/java/info/bukova/isspst/ui/search/RequirementResultTransformer.java new file mode 100644 index 00000000..0062bd5f --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/RequirementResultTransformer.java @@ -0,0 +1,14 @@ +package info.bukova.isspst.ui.search; + +import info.bukova.isspst.data.Requirement; + +public class RequirementResultTransformer extends AbstractResultTransformer implements ResultTransformer { + + @Override + protected void transform(Object object, SearchResult result) { + Requirement req = (Requirement)object; + result.setRecordName("Požadavek na nákup/službu: " + req.getNumser()); + result.setDescription(req.getDescription()); + } + +} diff --git a/src/main/java/info/bukova/isspst/ui/search/ResultTransformer.java b/src/main/java/info/bukova/isspst/ui/search/ResultTransformer.java new file mode 100644 index 00000000..32e0d053 --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/ResultTransformer.java @@ -0,0 +1,10 @@ +package info.bukova.isspst.ui.search; + +import info.bukova.isspst.EntityUrlResolver; + +public interface ResultTransformer { + + public SearchResult transformObject(Object object); + public void setUrlResolver(EntityUrlResolver resolver); + +} diff --git a/src/main/java/info/bukova/isspst/ui/search/SearchForm.java b/src/main/java/info/bukova/isspst/ui/search/SearchForm.java new file mode 100644 index 00000000..81f8c16a --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/SearchForm.java @@ -0,0 +1,58 @@ +package info.bukova.isspst.ui.search; + +import java.util.List; + +import org.zkoss.bind.annotation.Command; +import org.zkoss.bind.annotation.NotifyChange; +import org.zkoss.zk.ui.select.annotation.WireVariable; + +import info.bukova.isspst.UrlResolverHolder; +import info.bukova.isspst.data.BaseData; +import info.bukova.isspst.data.Requirement; +import info.bukova.isspst.data.TripRequirement; +import info.bukova.isspst.services.FullTextService; + +public class SearchForm { + + @WireVariable + private FullTextService fulltextService; + @WireVariable + private UrlResolverHolder urlResolverHolder; + private List results; + + private String keyWord; + + public void init() { + + } + + @Command + @NotifyChange("results") + public void doSearch() { + if (keyWord == null || keyWord.isEmpty()) { + return; + } + + //String[] fields = {"items.textItem", "description"}; + List result = fulltextService.globalSearch(keyWord); + //List result = fulltextService.search(Requirement.class, fields, keyWord); + + SearchListTransformer srt = new SearchListTransformer(urlResolverHolder); + results = srt.transform(result); + + System.out.println(result.size()); + } + + public String getKeyWord() { + return keyWord; + } + + public void setKeyWord(String keyWord) { + this.keyWord = keyWord; + } + + public List getResults() { + return results; + } + +} diff --git a/src/main/java/info/bukova/isspst/ui/search/SearchListTransformer.java b/src/main/java/info/bukova/isspst/ui/search/SearchListTransformer.java new file mode 100644 index 00000000..e357c717 --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/SearchListTransformer.java @@ -0,0 +1,41 @@ +package info.bukova.isspst.ui.search; + +import info.bukova.isspst.UrlResolverHolder; + +import java.util.ArrayList; +import java.util.List; + +public class SearchListTransformer { + + private UrlResolverHolder urlResolverHolder; + + public SearchListTransformer() { + urlResolverHolder = null; + } + + + + public SearchListTransformer(UrlResolverHolder urlResolverHolder) { + super(); + this.urlResolverHolder = urlResolverHolder; + } + + + + public List transform(List source) { + List ret = new ArrayList(); + + for (int i = 0; i < source.size(); i++) { + ResultTransformer transformer = TransformerFactory.transformerFor(source.get(i)); + if (urlResolverHolder != null) { + transformer.setUrlResolver(urlResolverHolder.resolverFor(source.get(i).getClass())); + } + ret.add(transformer.transformObject(source.get(i))); + } + + return ret; + } + + + +} diff --git a/src/main/java/info/bukova/isspst/ui/search/SearchResult.java b/src/main/java/info/bukova/isspst/ui/search/SearchResult.java new file mode 100644 index 00000000..f3ca3542 --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/SearchResult.java @@ -0,0 +1,73 @@ +package info.bukova.isspst.ui.search; + +import info.bukova.isspst.data.User; + +import java.util.Date; + +public class SearchResult { + + private String recordName; + private String description; + private String url; + private Date created; + private Date modified; + private User ownedBy; + private User modifiedBy; + + public String getRecordName() { + return recordName; + } + + public void setRecordName(String recordName) { + this.recordName = recordName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getModified() { + return modified; + } + + public void setModified(Date modified) { + this.modified = modified; + } + + public User getOwnedBy() { + return ownedBy; + } + + public void setOwnedBy(User ownedBy) { + this.ownedBy = ownedBy; + } + + public User getModifiedBy() { + return modifiedBy; + } + + public void setModifiedBy(User modifiedBy) { + this.modifiedBy = modifiedBy; + } + +} diff --git a/src/main/java/info/bukova/isspst/ui/search/TransformerFactory.java b/src/main/java/info/bukova/isspst/ui/search/TransformerFactory.java new file mode 100644 index 00000000..046cc542 --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/TransformerFactory.java @@ -0,0 +1,27 @@ +package info.bukova.isspst.ui.search; + +import info.bukova.isspst.data.Order; +import info.bukova.isspst.data.Requirement; +import info.bukova.isspst.data.TripBill; +import info.bukova.isspst.data.TripRequirement; + +public class TransformerFactory { + + public static ResultTransformer transformerFor(Object object) { + if (object instanceof TripBill) { + return new TripBillTransformer(); + } + if (object instanceof TripRequirement) { + return new TripRequirementTransformer(); + } + if (object instanceof Requirement) { + return new RequirementResultTransformer(); + } + if (object instanceof Order) { + return new OrderResultTransformer(); + } + + return new CommonResultTransformer(); + } + +} diff --git a/src/main/java/info/bukova/isspst/ui/search/TripBillTransformer.java b/src/main/java/info/bukova/isspst/ui/search/TripBillTransformer.java new file mode 100644 index 00000000..8b636959 --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/TripBillTransformer.java @@ -0,0 +1,14 @@ +package info.bukova.isspst.ui.search; + +import info.bukova.isspst.data.TripBill; + +public class TripBillTransformer extends AbstractResultTransformer implements ResultTransformer { + + @Override + protected void transform(Object object, SearchResult result) { + TripBill tb = (TripBill)object; + result.setRecordName("Vyúčtování služební cesty: " + tb.getRequirement().getNumser()); + result.setDescription("Z " + tb.getRequirement().getFrom() + " do " + tb.getRequirement().getTo() + " - " + tb.getRequirement().getDescription()); + } + +} diff --git a/src/main/java/info/bukova/isspst/ui/search/TripRequirementTransformer.java b/src/main/java/info/bukova/isspst/ui/search/TripRequirementTransformer.java new file mode 100644 index 00000000..17dfa26a --- /dev/null +++ b/src/main/java/info/bukova/isspst/ui/search/TripRequirementTransformer.java @@ -0,0 +1,14 @@ +package info.bukova.isspst.ui.search; + +import info.bukova.isspst.data.TripRequirement; + +public class TripRequirementTransformer extends AbstractResultTransformer implements ResultTransformer { + + @Override + protected void transform(Object object, SearchResult result) { + TripRequirement tr = (TripRequirement)object; + result.setRecordName("Žádost o služební cestu: " + tr.getNumser()); + result.setDescription("Z " + tr.getFrom() + " do " + tr.getTo() + " - " + tr.getDescription()); + } + +} diff --git a/src/main/resources/hibernate.cfg.xml b/src/main/resources/hibernate.cfg.xml index 70d8f8ef..aff526c7 100644 --- a/src/main/resources/hibernate.cfg.xml +++ b/src/main/resources/hibernate.cfg.xml @@ -32,5 +32,6 @@ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/spring/root-context.xml b/src/main/webapp/WEB-INF/spring/root-context.xml index aa91bad8..3777c234 100644 --- a/src/main/webapp/WEB-INF/spring/root-context.xml +++ b/src/main/webapp/WEB-INF/spring/root-context.xml @@ -52,8 +52,11 @@ ${jdbc.dialect} - false + true update + filesystem + /home/pepa/Dokumenty/dev/lucene + org.apache.lucene.analysis.cz.CzechAnalyzer @@ -423,4 +426,6 @@ + + diff --git a/src/main/webapp/search/searchForm.zul b/src/main/webapp/search/searchForm.zul new file mode 100644 index 00000000..297030da --- /dev/null +++ b/src/main/webapp/search/searchForm.zul @@ -0,0 +1,49 @@ + + + + + + + + + +