This is an old revision of the document!


Search Sample

This sample is basic example of querying database with some advanced features. Searching without any of the fields filled, will find all Persons from the database. Providing parameter values will filter result set. Selecting one or more Bank Advisers from the list will search only for Persons which have selected instances as their bank advisers (myBankAdvisers association end).

In additional options you can choose columns to be displayed, page size and whether result count to be displayed or not (this has impact on performance on large data sets). Clicking on any column header will sort results in ascending/descending order based on values in that column. Results can be exported as excel table.

Live example

UML Model

Business Logic Code

package rs.sol.sampleapps.search;
 
import java.util.Arrays;
 
import rs.sol.sampleapps.Person;
import rs.sol.soloist.server.guiconfiguration.components.GUISearchResultComponent.OrderByAnother;
import rs.sol.soloist.server.guiconfiguration.components.GUISearchResultComponent.Parameter;
import rs.sol.soloist.server.guiconfiguration.components.GUISearchResultComponent.Result;
import rs.sol.soloist.server.uml.queries.AssocEndTerm;
import rs.sol.soloist.server.uml.queries.AttributeTerm;
import rs.sol.soloist.server.uml.queries.ObjectTerm;
import rs.sol.soloist.server.uml.queries.SimpleQueryDefinition;
import rs.sol.soloist.server.uml.queries.builder.QueryBuilder;
 
public class PersonQueryBuilder extends QueryBuilder {
 
	private static final SimpleQueryDefinition prototypeQuery;
 
	@Parameter // @Parametar annotation means that QueryBuilder expects parameter value from element component named as annotated String
	@Result("Name") // @Result annotation means that column "Name" will be in result table
	public static final String NAME = "NAME";
 
	@Result("Person") @OrderByAnother(NAME) // @OrderByAnother - "Person" column will be order by name 
	public static final String PERSON = "PERSON";
 
	@Result("Age")
	public static final String AGE = "AGE";
 
	@Parameter @Result("Gender")
	public static final String GENDER = "GENDER";
 
	@Parameter @Result("Date of birth")
	public static final String DATE_OF_BIRTH = "DATE_OF_BIRTH";
 
	@Parameter @Result("Is married?")
	public static final String IS_MARRIED = "IS_MARRIED";
 
	@Parameter
	public static final String OLDER_THAN = "OLDER_THAN";
 
	@Parameter
	public static final String YOUNGER_THAN = "YOUNGER_THAN";
 
	@Parameter
	public static final String BANK_ADVISOR = "BANK_ADVISOR";
 
	public PersonQueryBuilder() {
		super(prototypeQuery);
 
		contributions.addAll(Arrays.asList(
				new ContributePrefixMatch(NAME),
				new ContributeEqual(IS_MARRIED),
				new ContributeEqual(GENDER),
				new ContributeEqual(DATE_OF_BIRTH),
				new ContributeGreaterOrEqual(OLDER_THAN),
				new ContributeLessOrEqual(YOUNGER_THAN),
				new ContributeIn(BANK_ADVISOR)
		));
 
		includeInResultOnce( // columns in result table, in this order
				PERSON,
				GENDER,
				DATE_OF_BIRTH,
				AGE,
				IS_MARRIED
		);
	}
 
	@Override
	public SimpleQueryDefinition buildCountQuery() {
		require(PERSON);
		return super.buildCountQuery();
	}
 
	@Override
	public SimpleQueryDefinition buildQuery() {
		require(PERSON);
		return super.buildQuery();
	}
 
	static {
		ObjectTerm root = new ObjectTerm(Person.FQ_TYPE_NAME).as(PERSON);
		new AttributeTerm(root, Person.PROPERTIES.name).as(NAME);
		new AttributeTerm(root, Person.PROPERTIES.gender).as(GENDER);
		new AttributeTerm(root, Person.PROPERTIES.age).as(AGE);
		new AttributeTerm(root, Person.PROPERTIES.dateOfBirth).as(DATE_OF_BIRTH);
		new AttributeTerm(root, Person.PROPERTIES.isMarried).as(IS_MARRIED);
		new AttributeTerm(root, Person.PROPERTIES.age).as(OLDER_THAN);
		new AttributeTerm(root, Person.PROPERTIES.age).as(YOUNGER_THAN);
		new AssocEndTerm(root, Person.PROPERTIES.myBankAdvisers).as(BANK_ADVISOR);
 
		prototypeQuery = new SimpleQueryDefinition(root).from(root);
	}
}

GUI Code

package rs.sol.sampleapps.search;
 
import rs.sol.sampleapps.BankAdviser;
import rs.sol.sampleapps.Gender;
import rs.sol.sampleapps.Person;
import rs.sol.sampleapps.gui.PersonSearch;
import rs.sol.soloist.helpers.init.DefaultContextInit;
import rs.sol.soloist.helpers.init.Initializer;
import rs.sol.soloist.helpers.init.InitializerFailedException;
import rs.sol.soloist.modelreader.Repository;
import rs.sol.soloist.server.builtindomains.builtindatatypes.Boolean;
import rs.sol.soloist.server.builtindomains.builtindatatypes.Date;
import rs.sol.soloist.server.builtindomains.builtindatatypes.Integer;
import rs.sol.soloist.server.builtindomains.builtindatatypes.Text;
import rs.sol.soloist.server.guiconfiguration.components.GUIApplicationComponent;
import rs.sol.soloist.server.guiconfiguration.components.GUIButtonComponent;
import rs.sol.soloist.server.guiconfiguration.components.GUIDeckComponent;
import rs.sol.soloist.server.guiconfiguration.components.GUILabelComponent;
import rs.sol.soloist.server.guiconfiguration.components.GUIPanelComponent;
import rs.sol.soloist.server.guiconfiguration.components.GUISearchPanelComponent;
import rs.sol.soloist.server.guiconfiguration.construction.GUIComponentBinding;
import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIElementComponent;
import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIInputKind;
import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIListWidget;
import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIMultipleElementWidget;
import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUISlotEditorKind;
import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUISubnodesInput;
import rs.sol.soloist.server.guiconfiguration.layout.CellLayoutData;
import rs.sol.soloist.server.guiconfiguration.layout.FlowLayout;
import rs.sol.soloist.server.guiconfiguration.layout.LayoutData;
import rs.sol.soloist.server.guiconfiguration.style.GUIBindingsFeature;
import rs.sol.soloist.server.guiconfiguration.style.GUIContext;
import rs.sol.soloist.server.guiconfiguration.style.GUIObjectSetting;
import rs.sol.soloist.server.guiconfiguration.style.GUIPictureFeature;
import rs.sol.soloist.server.guiconfiguration.style.GUITextFeature;
import rs.sol.soloist.server.server.SoloistServiceServlet;
 
public enum Search implements Initializer {
 
	INSTANCE;
 
	@Override
	public void init() throws InitializerFailedException {
		GUIApplicationComponent application = new GUIApplicationComponent();
		application.name.set(Text.fromString("SearchSample"));
		SoloistServiceServlet.registerApplication(application);
 
		GUIPanelComponent root = GUIPanelComponent.createFlow(application);
 
		GUILabelComponent title = GUILabelComponent.create(root, "Search");
		title.styleName.set(Text.fromString("titleStyle"));
 
		GUIPanelComponent topPanel = GUIPanelComponent.createFlow(root);
		topPanel.styleName.set(Text.fromString("topPanel"));
 
		GUIDeckComponent mainDeck = GUIDeckComponent.create(topPanel);
 
		GUIPanelComponent wrapPanel = GUIPanelComponent.createFlow(mainDeck);
		GUISearchPanelComponent searchForm = GUISearchPanelComponent.create(wrapPanel, new FlowLayout());
		//GUISearchPanelComponent binds element components implicitly between search form and query builder based on components' names 
		searchForm.styleName.set(Text.fromString("form searchForm"));
 
		GUIPanelComponent table = GUIPanelComponent.createTable(searchForm);
		table.styleName.set(Text.fromString("table"));
		LayoutData.setSize(table, "100%", null);
 
		int row = 0;
		GUIElementComponent.createInput(table, PersonQueryBuilder.NAME, Text.CLASSIFIER, row++, 1);  // name needs to be provided, in this case PersonQueryBuilder.NAME constant
		GUIElementComponent.createInput(table, PersonQueryBuilder.GENDER, Repository.getRepository().getEnumeration(Gender.FQ_TYPE_NAME), row++, 1);
		GUIElementComponent.createInput(table, PersonQueryBuilder.DATE_OF_BIRTH, Date.CLASSIFIER, row++, 1);
		GUIElementComponent.createInput(table, PersonQueryBuilder.IS_MARRIED, Boolean.CLASSIFIER, row++, 1);
		GUIElementComponent.createInput(table, PersonQueryBuilder.OLDER_THAN, Integer.CLASSIFIER, row++, 1);
		GUIElementComponent.createInput(table, PersonQueryBuilder.YOUNGER_THAN, Integer.CLASSIFIER, row++, 1);
 
		row = 0;
		GUILabelComponent.create(table, "Name", row++, 0).styleName.set(Text.fromString("formLabel"));
		GUILabelComponent.create(table, "Gender", row++, 0).styleName.set(Text.fromString("formLabel"));
		GUILabelComponent.create(table, "Date of birth", row++, 0).styleName.set(Text.fromString("formLabel"));
		GUILabelComponent.create(table, "Is married?", row++, 0).styleName.set(Text.fromString("formLabel"));
		GUILabelComponent.create(table, "Older than", row++, 0).styleName.set(Text.fromString("formLabel"));
		GUILabelComponent.create(table, "Younger than", row++, 0).styleName.set(Text.fromString("formLabel"));
 
		GUILabelComponent.create(wrapPanel, "Search by Bank Advisers:");
		GUISearchPanelComponent searchList = GUISearchPanelComponent.create(wrapPanel, new FlowLayout());
		GUIElementComponent bankAdvisors = GUIElementComponent.createInput(searchList, PersonQueryBuilder.BANK_ADVISOR, new GUIListWidget(),
				GUISubnodesInput.create(BankAdviser.CLASSIFIER), null); 
		GUIInputKind.get(bankAdvisors).upperBound.set(Integer.valueOf(-1));
		CellLayoutData.setSize(bankAdvisors, "250px", "154px");
		bankAdvisors.styleName.set(Text.fromString("listWidget"));
 
		GUIButtonComponent btnAll = GUIButtonComponent.create(wrapPanel, "Select All");
		GUIButtonComponent btnNone = GUIButtonComponent.create(wrapPanel, "Select None");
		GUIComponentBinding.create(btnAll.click, GUIMultipleElementWidget.get(bankAdvisors).selectAll);
		GUIComponentBinding.create(btnNone.click, GUIMultipleElementWidget.get(bankAdvisors).unselectAll);
 
		GUIPanelComponent buttonPanel = GUIPanelComponent.createFlow(wrapPanel);
		buttonPanel.styleName.set(Text.fromString("searchButtons"));
 
		GUIButtonComponent searchButton = GUIButtonComponent.create(buttonPanel, "Search");
		searchButton.styleName.set(Text.fromString("submitButton"));
 
		GUIButtonComponent resetButton = GUIButtonComponent.create(buttonPanel, "Reset");
		resetButton.styleName.set(Text.fromString("submitButton"));
 
		GUIPanelComponent searchTable = GUIPanelComponent.createFlow(wrapPanel);
		searchTable.styleName.set(Text.fromString("searchPanel"));
 
		PersonSearch searchResult = new PersonSearch();
		searchResult.parent.set(searchTable);
		searchResult.doInitialSearch.set(Boolean.FALSE);
		searchForm.dynamicBindingDest.set(searchResult); // binds all fields in search form with corresponding query builder
		searchList.dynamicBindingDest.set(searchResult);
 
		LayoutData.setSize(searchResult, "100%", null);
 
		GUIComponentBinding.create(searchButton.click, searchResult.search);
		GUIComponentBinding.create(resetButton.click, searchForm.reset);
		GUIComponentBinding.create(resetButton.click, searchResult.clearContents);
 
		GUIComponentBinding.create(wrapPanel.output, searchResult.search);
 
		GUIPanelComponent personDetails = GUIPanelComponent.createTable(mainDeck);
		personDetails.styleName.set(Text.fromString("searchDetails"));
 
		GUIPanelComponent detailsTable = GUIPanelComponent.createTable(personDetails);
		application.context.set(createContextAndStyles(detailsTable));
 
		createDetails(detailsTable, wrapPanel);
	}
 
	/**
	 * Person details editors
	 */
	private void createDetails(GUIPanelComponent personDetails, GUIPanelComponent backTo) {
		int row = 0;
		GUILabelComponent.create(personDetails, "Name: ", row, 0);
		GUIElementComponent nameEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.name, row++, 1);
 
		GUILabelComponent.create(personDetails, "Gender: ", row, 0);
		GUIElementComponent genderEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.gender, row++, 1);
 
		GUILabelComponent.create(personDetails, "Age: ", row, 0);
		GUIElementComponent ageEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.age, row++, 1);
 
		GUILabelComponent.create(personDetails, "Date of birth: ", row, 0);
		GUIElementComponent dateOfBirthEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.dateOfBirth, row++, 1);
 
		GUILabelComponent.create(personDetails, "Height [m]: ", row, 0);
		GUIElementComponent heightEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.height, row++, 1);
 
		GUILabelComponent.create(personDetails, "Is married: ", row, 0);
		GUIElementComponent isMarriedEditor = GUIElementComponent.createSlotEditor(personDetails, Person.PROPERTIES.isMarried, row++, 1);
 
		GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(nameEditor).element);
		GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(genderEditor).element);
		GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(ageEditor).element);
		GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(dateOfBirthEditor).element);
		GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(heightEditor).element);
		GUIComponentBinding.create(personDetails.input, GUISlotEditorKind.get(isMarriedEditor).element);
 
		GUIButtonComponent backButton = GUIButtonComponent.create(personDetails, "Back", row++, 0);
		GUIComponentBinding.create(backButton.click, backTo.show);
	}
 
	private GUIContext createContextAndStyles(GUIPanelComponent personDetails) {
		GUIContext context = new GUIContext();
		context.supercontext.set(DefaultContextInit.getRoot());
 
		// how will Person objects look like in the GUI?
		GUIObjectSetting person = GUIObjectSetting.create(context, Person.CLASSIFIER);
		GUITextFeature.createName(person, Person.PROPERTIES.name);
		GUIPictureFeature.createSmallIcon(person, "images/icons/person.png");
 
		GUIBindingsFeature bf = GUIBindingsFeature.create(person);
		GUIComponentBinding.create(bf.doubleClick, personDetails.input); // doubleClick signal carries Person object
		// panel's input pin is unfortunately named, it is actually input/output pin, and can be used to send messages to panel's internal components (see createDetails() method)
		GUIComponentBinding.create(bf.doubleClick, personDetails.show); // double-clicking on person in result table will show person's details
 
		return context;
	}
}
Print/export