Rozdělané fulltextové vyhledávání

Verze_2.0
Josef Rokos 10 years ago
parent b1818546c0
commit 02311ae5dd

@ -215,16 +215,20 @@
<!-- Hibernate --> <!-- Hibernate -->
<dependency> <dependency>
<groupId>org.hibernate</groupId> <groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId> <artifactId>hibernate-core</artifactId>
<version>4.2.8.Final</version> <version>4.2.8.Final</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.hibernate</groupId> <groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId> <artifactId>hibernate-validator</artifactId>
<version>4.3.0.Final</version> <version>4.3.0.Final</version>
</dependency> </dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search</artifactId>
<version>4.4.6.Final</version>
</dependency>
<!-- ZK --> <!-- ZK -->
<dependency> <dependency>

@ -11,6 +11,7 @@ import info.bukova.isspst.data.User;
import info.bukova.isspst.reporting.Report; import info.bukova.isspst.reporting.Report;
import info.bukova.isspst.reporting.ReportMapping; import info.bukova.isspst.reporting.ReportMapping;
import info.bukova.isspst.reporting.ReportType; import info.bukova.isspst.reporting.ReportType;
import info.bukova.isspst.services.FullTextService;
import info.bukova.isspst.services.munits.MUnitService; import info.bukova.isspst.services.munits.MUnitService;
import info.bukova.isspst.services.numberseries.NumberSeriesService; import info.bukova.isspst.services.numberseries.NumberSeriesService;
import info.bukova.isspst.services.requirement.RequirementTypeService; import info.bukova.isspst.services.requirement.RequirementTypeService;
@ -40,6 +41,7 @@ public class AppInitListener implements ServletContextListener {
private NumberSeriesService nsService; private NumberSeriesService nsService;
private RequirementTypeService reqTypeService; private RequirementTypeService reqTypeService;
private GlobalSettingsService gSettingsService; private GlobalSettingsService gSettingsService;
private FullTextService ftService;
@Override @Override
public void contextDestroyed(ServletContextEvent arg0) { public void contextDestroyed(ServletContextEvent arg0) {
@ -59,6 +61,7 @@ public class AppInitListener implements ServletContextListener {
nsService =ctx.getBean(NumberSeriesService.class); nsService =ctx.getBean(NumberSeriesService.class);
gSettingsService = ctx.getBean(GlobalSettingsService.class); gSettingsService = ctx.getBean(GlobalSettingsService.class);
reqTypeService = ctx.getBean(RequirementTypeService.class); reqTypeService = ctx.getBean(RequirementTypeService.class);
ftService = ctx.getBean(FullTextService.class);
userService.grantAdmin(); userService.grantAdmin();
checkMUnits(); checkMUnits();
@ -69,11 +72,16 @@ public class AppInitListener implements ServletContextListener {
this.checkNumberSeries(); this.checkNumberSeries();
checkReqTypes(); checkReqTypes();
this.checkGlobalSettings(); this.checkGlobalSettings();
buildFulltext();
userService.removeAccess(); userService.removeAccess();
loadModuleReports(); loadModuleReports();
} }
private void buildFulltext() {
ftService.reindex();
}
private void checkMUnits() private void checkMUnits()
{ {
List<MUnit> mUnits = mUnitsService.getAll(); List<MUnit> mUnits = mUnitsService.getAll();

@ -4,11 +4,13 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import info.bukova.isspst.data.Order;
import info.bukova.isspst.data.Permission; import info.bukova.isspst.data.Permission;
import info.bukova.isspst.data.PermissionType; import info.bukova.isspst.data.PermissionType;
import info.bukova.isspst.data.Requirement; import info.bukova.isspst.data.Requirement;
import info.bukova.isspst.data.RequirementType; import info.bukova.isspst.data.RequirementType;
import info.bukova.isspst.data.Role; import info.bukova.isspst.data.Role;
import info.bukova.isspst.data.TripBill;
import info.bukova.isspst.data.TripRequirement; import info.bukova.isspst.data.TripRequirement;
import info.bukova.isspst.reporting.Report; import info.bukova.isspst.reporting.Report;
import info.bukova.isspst.reporting.ReportMapping; import info.bukova.isspst.reporting.ReportMapping;
@ -141,5 +143,7 @@ public class Constants {
public final static Map<Class<?>, String> URL_MAP = Collections.unmodifiableMap(new HashMap<Class<?>, String>() {{ public final static Map<Class<?>, String> URL_MAP = Collections.unmodifiableMap(new HashMap<Class<?>, String>() {{
put(Requirement.class, "/main/orders/"); put(Requirement.class, "/main/orders/");
put(TripRequirement.class, "/main/trips/requirements/"); put(TripRequirement.class, "/main/trips/requirements/");
put(Order.class, "/main/orders/created/");
put(TripBill.class, "/main/trips/bill/");
}} ); }} );
} }

@ -29,7 +29,7 @@ public class RequirementUrlResolver implements EntityUrlResolver {
Requirement req = (Requirement)entity; 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()); return defaultUrl + Constants.URL_MAP.get(req.getClass()) + "material/?select=" + String.valueOf(req.getId());
} else { } else {
return defaultUrl + Constants.URL_MAP.get(req.getClass()) + "services/?select=" + String.valueOf(req.getId()); return defaultUrl + Constants.URL_MAP.get(req.getClass()) + "services/?select=" + String.valueOf(req.getId());

@ -7,11 +7,18 @@ import java.util.List;
import javax.persistence.Embeddable; 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 @Embeddable
@Indexed
public class AddressEmb public class AddressEmb
{ {
private int id; private int id;
@Field(index = Index.YES, analyze = Analyze.YES)
private String company; private String company;
private String department; private String department;
private String contactName; private String contactName;

@ -11,7 +11,11 @@ import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.persistence.Transient; import javax.persistence.Transient;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
@MappedSuperclass @MappedSuperclass
@Indexed
public abstract class BaseData implements OwnedDataModel { public abstract class BaseData implements OwnedDataModel {
@Id @Id
@ -24,9 +28,11 @@ public abstract class BaseData implements OwnedDataModel {
private Date modified; private Date modified;
@ManyToOne(fetch=FetchType.LAZY) @ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="OWNED_BY_ID") @JoinColumn(name="OWNED_BY_ID")
@IndexedEmbedded
private User ownedBy; private User ownedBy;
@ManyToOne(fetch=FetchType.LAZY) @ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="MODIFIED_BY_ID") @JoinColumn(name="MODIFIED_BY_ID")
@IndexedEmbedded
private User modifiedBy; private User modifiedBy;
@Transient @Transient
private boolean valid; private boolean valid;

@ -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;
}
}

@ -16,9 +16,15 @@ import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption; 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 @Entity
@Table(name = "ORDERS") @Table(name = "ORDERS")
@Indexed
public class Order extends BaseData implements Cloneable 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 = "street", column = @Column(name = "SUPPLIER_STREET")),
@AttributeOverride(name = "web", column = @Column(name = "SUPPLIER_WEB")), @AttributeOverride(name = "web", column = @Column(name = "SUPPLIER_WEB")),
@AttributeOverride(name = "zipCode", column = @Column(name = "SUPPLIER_ZIP_CODE")) }) @AttributeOverride(name = "zipCode", column = @Column(name = "SUPPLIER_ZIP_CODE")) })
@IndexedEmbedded
private AddressEmb suplier; private AddressEmb suplier;
@Embedded @Embedded
@ -95,10 +102,12 @@ public class Order extends BaseData implements Cloneable
private String deliveryType; private String deliveryType;
@Column(name = "DESCRIPTION") @Column(name = "DESCRIPTION")
@Field(index = Index.YES, analyze = Analyze.YES)
private String description; private String description;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "order", orphanRemoval = true) @OneToMany(cascade = CascadeType.ALL, mappedBy = "order", orphanRemoval = true)
@LazyCollection(LazyCollectionOption.TRUE) @LazyCollection(LazyCollectionOption.TRUE)
@IndexedEmbedded
private List<OrderItem> items; private List<OrderItem> items;
@Column(name = "TOTAL", precision = 15, scale = 4) @Column(name = "TOTAL", precision = 15, scale = 4)

@ -12,8 +12,14 @@ import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; 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 @Entity
@Table(name = "ORDER_ITEM") @Table(name = "ORDER_ITEM")
@Indexed
public class OrderItem public class OrderItem
{ {
@ -26,9 +32,11 @@ public class OrderItem
private String code; private String code;
@Column(name = "NAME") @Column(name = "NAME")
@Field(index = Index.YES, analyze = Analyze.YES)
private String name; private String name;
@Column(name = "TEXTITEM") @Column(name = "TEXTITEM")
@Field(index = Index.YES, analyze = Analyze.YES)
private String textItem; private String textItem;
@Column(name = "QUANTITY", precision = 15, scale = 4) @Column(name = "QUANTITY", precision = 15, scale = 4)
@ -44,6 +52,7 @@ public class OrderItem
private BigDecimal total; private BigDecimal total;
@Column(name = "DESCRIPTION") @Column(name = "DESCRIPTION")
@Field(index = Index.YES, analyze = Analyze.YES)
private String description; private String description;
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)

@ -12,11 +12,16 @@ import javax.persistence.FetchType;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
@Entity @Entity
@Table(name = "REQUIREMENT") @Table(name = "REQUIREMENT")
@Indexed
public class Requirement extends RequirementBase public class Requirement extends RequirementBase
{ {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "requirement", cascade = CascadeType.ALL, orphanRemoval = true) @OneToMany(fetch = FetchType.LAZY, mappedBy = "requirement", cascade = CascadeType.ALL, orphanRemoval = true)
@IndexedEmbedded
private List<RequirementItem> items; private List<RequirementItem> items;
@Column(name = "DELIVERYDATE") @Column(name = "DELIVERYDATE")

@ -17,8 +17,13 @@ import javax.persistence.OrderBy;
import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption; 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 @MappedSuperclass
@Indexed
public class RequirementBase extends BaseData implements FilterableRequirement { public class RequirementBase extends BaseData implements FilterableRequirement {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@ -33,6 +38,7 @@ public class RequirementBase extends BaseData implements FilterableRequirement {
@Column(name = "REQ_DATE") @Column(name = "REQ_DATE")
private Date reqDate; private Date reqDate;
@Column(name = "DESCRIPTION") @Column(name = "DESCRIPTION")
@Field(index = Index.YES, analyze = Analyze.YES)
private String description; private String description;
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "CENTRE_ID") @JoinColumn(name = "CENTRE_ID")

@ -12,8 +12,15 @@ import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; 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 @Entity
@Table(name = "REQUIREMENT_ITEMS") @Table(name = "REQUIREMENT_ITEMS")
@Indexed
public class RequirementItem public class RequirementItem
{ {
@Id @Id
@ -33,9 +40,11 @@ public class RequirementItem
private String code; private String code;
@Column(name = "NAME") @Column(name = "NAME")
@Field(index = Index.YES, analyze = Analyze.YES)
private String name; private String name;
@Column(name = "TEXTITEM") @Column(name = "TEXTITEM")
@Field(index = Index.YES, analyze = Analyze.YES)
private String textItem; private String textItem;
@Column(name = "QUANTITY", precision=15, scale=4) @Column(name = "QUANTITY", precision=15, scale=4)
@ -51,6 +60,7 @@ public class RequirementItem
private BigDecimal total; private BigDecimal total;
@Column(name = "DESCRIPTION") @Column(name = "DESCRIPTION")
@Field(index = Index.YES, analyze = Analyze.YES)
private String description; private String description;
@Column(name = "DELIVERED") @Column(name = "DELIVERED")

@ -16,9 +16,12 @@ import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption; import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
@Entity @Entity
@Table(name = "TRIP_BILL") @Table(name = "TRIP_BILL")
@Indexed
public class TripBill extends BaseData { public class TripBill extends BaseData {
@OneToOne(fetch = FetchType.EAGER) @OneToOne(fetch = FetchType.EAGER)
@ -44,6 +47,10 @@ public class TripBill extends BaseData {
private BigDecimal downPayment; private BigDecimal downPayment;
@Column(name = "TOTAL", precision = 15, scale = 4) @Column(name = "TOTAL", precision = 15, scale = 4)
private BigDecimal total; private BigDecimal total;
@OneToMany
@LazyCollection(LazyCollectionOption.TRUE)
@IndexedEmbedded
private List<FileMetainfo> attachedFiles;
public TripBill() { public TripBill() {
billItems = new ArrayList<TripBillItem>(); billItems = new ArrayList<TripBillItem>();
@ -121,4 +128,12 @@ public class TripBill extends BaseData {
this.total = total; this.total = total;
} }
public List<FileMetainfo> getAttachedFiles() {
return attachedFiles;
}
public void setAttachedFiles(List<FileMetainfo> attachedFiles) {
this.attachedFiles = attachedFiles;
}
} }

@ -11,18 +11,27 @@ import javax.persistence.Entity;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.ManyToMany; import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption; 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 @Entity
@Table(name = "TRIPREQUIREMENT") @Table(name = "TRIPREQUIREMENT")
@Indexed
public class TripRequirement extends RequirementBase { public class TripRequirement extends RequirementBase {
@Column(name = "TRIP_FROM") @Column(name = "TRIP_FROM")
@Field(index = Index.YES, analyze = Analyze.YES)
private String from; private String from;
@Column(name = "TRIP_TO") @Column(name = "TRIP_TO")
@Field(index = Index.YES, analyze = Analyze.YES)
private String to; private String to;
@Column(name = "TRIP_DATE") @Column(name = "TRIP_DATE")
private Date tripDate; private Date tripDate;
@ -40,6 +49,10 @@ public class TripRequirement extends RequirementBase {
private Boolean requireDownPayment; private Boolean requireDownPayment;
@Column(name = "DOWN_PAYMENT", precision = 15, scale = 4) @Column(name = "DOWN_PAYMENT", precision = 15, scale = 4)
private BigDecimal downPayment; private BigDecimal downPayment;
@OneToMany
@LazyCollection(LazyCollectionOption.TRUE)
@IndexedEmbedded
private List<FileMetainfo> attachedFiles;
public TripRequirement() { public TripRequirement() {
this.setOwnedBy(new User()); this.setOwnedBy(new User());
@ -118,4 +131,12 @@ public class TripRequirement extends RequirementBase {
this.downPayment = downPayment; this.downPayment = downPayment;
} }
public List<FileMetainfo> getAttachedFiles() {
return attachedFiles;
}
public void setAttachedFiles(List<FileMetainfo> attachedFiles) {
this.attachedFiles = attachedFiles;
}
} }

@ -14,10 +14,15 @@ import javax.persistence.JoinTable;
import javax.persistence.ManyToMany; import javax.persistence.ManyToMany;
import javax.persistence.Table; 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; import org.springframework.security.core.userdetails.UserDetails;
@Entity @Entity
@Table(name="USER") @Table(name="USER")
@Indexed
public class User extends Member implements UserDetails, DataModel { public class User extends Member implements UserDetails, DataModel {
/** /**
@ -32,8 +37,10 @@ public class User extends Member implements UserDetails, DataModel {
@Column(name="ENABLED") @Column(name="ENABLED")
private boolean enabled; private boolean enabled;
@Column(name="FIRST_NAME") @Column(name="FIRST_NAME")
@Field(index = Index.YES, analyze = Analyze.YES)
private String firstName; private String firstName;
@Column(name="LAST_NAME") @Column(name="LAST_NAME")
@Field(index = Index.YES, analyze = Analyze.YES)
private String lastName; private String lastName;
@Column(name="PERSONAL_NUMBER") @Column(name="PERSONAL_NUMBER")
private String personalNumber; private String personalNumber;

@ -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);
}

@ -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<Class<?>> classesForSearch;
private Map<Class<?>, String[]> fields;
private List<Class<?>> nestedClasses;
public FullTextServiceImpl() {
nestedClasses = new ArrayList<Class<?>>();
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<Object> result = new ArrayList<Object>();
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<Class<?>> classesForSearch() {
if (classesForSearch != null) {
return classesForSearch;
}
classesForSearch = new ArrayList<Class<?>>();
fields = new HashMap<Class<?>, 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<String> res = new ArrayList<String>();
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;
}
}

@ -4,8 +4,10 @@ import java.beans.BeanInfo;
import java.beans.IntrospectionException; import java.beans.IntrospectionException;
import java.beans.Introspector; import java.beans.Introspector;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
public class ReflectionTools { public class ReflectionTools {
@ -78,4 +80,23 @@ public class ReflectionTools {
return getEntityFields(entity.getClass()); return getEntityFields(entity.getClass());
} }
public static List<Field> getFields(Object entity) {
if (entity == null) {
return null;
}
return getFields(entity.getClass());
}
public static List<Field> getFields(Class<?> clazz) {
List<Field> ret = new ArrayList<Field>();
ret.addAll(Arrays.asList(clazz.getDeclaredFields()));
if (!clazz.getSuperclass().equals(Object.class)) {
ret.addAll(getFields(clazz.getSuperclass()));
}
return ret;
}
} }

@ -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;
}
}

@ -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());
}
}

@ -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());
}
}

@ -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());
}
}

@ -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);
}

@ -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<SearchResult> 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<SearchResult> getResults() {
return results;
}
}

@ -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<SearchResult> transform(List<?> source) {
List<SearchResult> ret = new ArrayList<SearchResult>();
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;
}
}

@ -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;
}
}

@ -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();
}
}

@ -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());
}
}

@ -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());
}
}

@ -32,5 +32,6 @@
<mapping class="info.bukova.isspst.data.OrderItem"></mapping> <mapping class="info.bukova.isspst.data.OrderItem"></mapping>
<mapping class="info.bukova.isspst.data.Invoicing"></mapping> <mapping class="info.bukova.isspst.data.Invoicing"></mapping>
<mapping class="info.bukova.isspst.data.InvoicingItem"></mapping> <mapping class="info.bukova.isspst.data.InvoicingItem"></mapping>
<mapping class="info.bukova.isspst.data.FileMetainfo"></mapping>
</session-factory> </session-factory>
</hibernate-configuration> </hibernate-configuration>

@ -52,8 +52,11 @@
<property name="hibernateProperties"> <property name="hibernateProperties">
<props> <props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop> <prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">false</prop> <prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.search.default.directory_provider">filesystem</prop>
<prop key="hibernate.search.default.indexBase">/home/pepa/Dokumenty/dev/lucene</prop>
<prop key="hibernate.search.analyzer">org.apache.lucene.analysis.cz.CzechAnalyzer</prop>
<!-- <prop key="hibernate.enable_lazy_load_no_trans">true</prop> --> <!-- <prop key="hibernate.enable_lazy_load_no_trans">true</prop> -->
</props> </props>
</property> </property>
@ -423,4 +426,6 @@
<property name="validator" ref="validator"/> <property name="validator" ref="validator"/>
</bean> </bean>
<bean id="fulltextService" class="info.bukova.isspst.services.FullTextServiceImpl"/>
</beans> </beans>

@ -0,0 +1,49 @@
<?page title="Search" contentType="text/html;charset=UTF-8"?>
<zk>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window title="Search" border="normal" closable="true"
apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('info.bukova.isspst.ui.search.SearchForm')"
vflex="1">
<vbox width="100%"
vflex="1">
<hbox>
<textbox value="@bind(vm.keyWord)" />
<button label="Hledat" onClick="@command('doSearch')" />
</hbox>
<panel hflex="1" vflex="1">
<panelchildren style="overflow:auto;">
<vbox children="@load(vm.results)" width="100%">
<template name="children">
<vbox width="100%">
<separator bar="true" width="100%"/>
<label value="@load(each.recordName)" style="font-weight: bold; font-size:14px;"/>
<label value="@load(each.description)"/>
<hbox>
<label value="Vytvořeno: "/>
<label value="@load(each.created)"/>
</hbox>
<hbox>
<label value="Vytvořil: "/>
<label value="@load(each.ownedBy)"/>
</hbox>
<hbox>
<label value="Změněno: "/>
<label value="@load(each.modified)"/>
</hbox>
<hbox>
<label value="Změnil: "/>
<label value="@load(each.modifiedBy)"/>
</hbox>
<a href="@load(each.url)" label="@load(each.url)"/>
</vbox>
</template>
</vbox>
</panelchildren>
</panel>
</vbox>
</window>
</zk>
Loading…
Cancel
Save