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