├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── app ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── rotabuilder │ └── app │ ├── DomainAppAppManifest.java │ ├── DomainAppAppModule.java │ ├── DomainAppTestManifest.java │ └── services │ ├── homepage │ ├── HomePageService.java │ ├── HomePageViewModel.java │ ├── HomePageViewModel.layout.xml │ └── HomePageViewModel.png │ ├── registration │ └── AppUserRegistrationService.java │ └── tenancyevaluator │ ├── ApplicationTenancyEvaluatorForRoster.java │ ├── TenancySwitcher.java │ └── UserProfileServiceShowingTenancy.java ├── dom ├── log4j.properties ├── pom.xml └── src │ ├── main │ └── java │ │ ├── META-INF │ │ └── persistence.xml │ │ └── com │ │ └── rotabuilder │ │ └── dom │ │ ├── DomainAppDomManifest.java │ │ ├── DomainAppDomainModule.java │ │ ├── domain │ │ ├── contract │ │ │ ├── BooleanContractLine.java │ │ │ ├── Contract.java │ │ │ ├── Contract.layout.xml │ │ │ ├── ContractLine.java │ │ │ ├── ContractLineType.java │ │ │ ├── ContractMenu.java │ │ │ ├── ContractRepository.java │ │ │ ├── MinMaxContractLine.java │ │ │ └── PatternContractLine.java │ │ ├── employee │ │ │ ├── DayOffRequest.java │ │ │ ├── DayOnRequest.java │ │ │ ├── Employee.java │ │ │ ├── Employee.layout.xml │ │ │ ├── Employee.png │ │ │ ├── EmployeeMenu.java │ │ │ ├── EmployeeRepository.java │ │ │ ├── ShiftOffRequest.java │ │ │ ├── ShiftOnRequest.java │ │ │ ├── Skill.java │ │ │ └── SkillProficiency.java │ │ ├── pattern │ │ │ ├── DayOfWeek.java │ │ │ ├── FreeBefore2DaysWithAWorkDayPattern.java │ │ │ ├── Pattern.java │ │ │ ├── PatternMenu.java │ │ │ ├── PatternsRepository.java │ │ │ ├── ShiftType2DaysPattern.java │ │ │ ├── ShiftType3DaysPattern.java │ │ │ ├── WeekendDefinition.java │ │ │ └── WorkBeforeFreeSequencePattern.java │ │ ├── shift │ │ │ ├── Shift.java │ │ │ ├── Shift.png │ │ │ ├── ShiftAssignment.java │ │ │ ├── ShiftDate.java │ │ │ ├── ShiftMenu.java │ │ │ ├── ShiftRepository.java │ │ │ ├── ShiftService.java │ │ │ ├── ShiftType.java │ │ │ ├── ShiftType.layout.xml │ │ │ └── ShiftTypeSkillRequirement.java │ │ └── solver │ │ │ ├── AbstractPersistable.java │ │ │ ├── EmployeeRoster.java │ │ │ ├── EmployeeRosterParametrization.java │ │ │ ├── EmployeeStrengthComparator.java │ │ │ ├── MovableShiftAssignmentSelectionFilter.java │ │ │ ├── PersistableIdComparator.java │ │ │ └── ShiftAssignmentDifficultyComparator.java │ │ └── solver │ │ ├── drools │ │ ├── EmployeeAssignmentTotal.java │ │ ├── EmployeeConsecutiveAssignmentEnd.java │ │ ├── EmployeeConsecutiveAssignmentStart.java │ │ ├── EmployeeConsecutiveWeekendAssignmentEnd.java │ │ ├── EmployeeConsecutiveWeekendAssignmentStart.java │ │ ├── EmployeeFreeSequence.java │ │ ├── EmployeeWeekendSequence.java │ │ └── EmployeeWorkSequence.java │ │ └── move │ │ ├── EmployeeChangeMove.java │ │ ├── EmployeeMultipleChangeMove.java │ │ ├── EmployeeRosteringMoveHelper.java │ │ ├── ShiftAssignmentSwapMove.java │ │ └── factory │ │ ├── EmployeeChangeMoveFactory.java │ │ ├── ShiftAssignmentPillarPartSwapMoveFactory.java │ │ ├── ShiftAssignmentSequenceSwitchLength2MoveFactory.java │ │ ├── ShiftAssignmentSequenceSwitchLength3MoveFactory.java │ │ └── ShiftAssignmentSwapMoveFactory.java │ └── test │ └── java │ └── com │ └── rotabuilder │ └── dom │ └── domain │ └── employee │ ├── EmployeeRepositoryTest.java │ └── EmployeeTest.java ├── fixture ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── rotabuilder │ └── fixture │ ├── DomainAppFixtureModule.java │ ├── DomainAppFixtureScriptsSpecificationProvider.java │ ├── dom │ ├── ContractCreate.java │ ├── ContractTearDown.java │ ├── EmployeeCreate.java │ ├── EmployeeTearDown.java │ ├── PatternCreate.java │ ├── PatternTearDown.java │ ├── RequestCreate.java │ ├── RequestlTearDown.java │ ├── ShiftCreate.java │ ├── ShiftDateCreate.java │ ├── ShiftDateTearDown.java │ ├── ShiftTearDown.java │ ├── ShiftTypeCreate.java │ ├── ShiftTypeTearDown.java │ ├── SkillCreate.java │ └── SkillTearDown.java │ └── scenarios │ ├── MyFixtureScript.java │ ├── RecreateContracts.java │ ├── RecreateEmployees.java │ ├── RecreatePatterns.java │ ├── RecreateShiftDates.java │ ├── RecreateShiftType.java │ ├── RecreateSkills.java │ └── UserFixture.java ├── integtests ├── logging.properties ├── pom.xml └── src │ └── test │ └── java │ └── com │ └── rotabuilder │ └── integtests │ └── modules │ ├── DomainAppIntegTest.java │ ├── DomainAppSystemInitializer.java │ ├── EmployeeMenu_IntegTest.java │ └── Employee_IntegTest.java ├── pom.xml └── webapp ├── ide ├── eclipse │ └── launch │ │ ├── .gitignore │ │ ├── SimpleApp-PROTOTYPE-with-fixtures-bypass-security.launch │ │ ├── SimpleApp-PROTOTYPE-with-fixtures.launch │ │ ├── SimpleApp-PROTOTYPE.launch │ │ └── SimpleApp-SERVER.launch └── intellij │ └── launch │ ├── README.txt │ ├── SimpleApp_PROTOTYPE.xml │ ├── SimpleApp_PROTOTYPE_with_fixtures-bypass-security.xml │ ├── SimpleApp_PROTOTYPE_with_fixtures.xml │ ├── SimpleApp_SERVER.xml │ └── SimpleApp__enhance_only_.xml ├── lib └── .gitignore ├── pom.xml └── src └── main ├── java └── com │ └── rotabuilder │ └── webapp │ ├── DomainApplication.java │ └── footer │ ├── CustomFooterPanel.java │ ├── CustomFooterPanelFactory.java │ └── MyComponentFactoryRegistrar.java ├── jettyconsole ├── isis-banner.pdn └── isis-banner.png ├── resources ├── com │ └── rotabuilder │ │ └── webapp │ │ ├── DomainApplication.properties │ │ ├── footer │ │ └── CustomFooterPanel.html │ │ └── welcome.html ├── data │ └── nurserostering │ │ ├── export │ │ └── solution.xsd │ │ ├── import │ │ ├── competition.xsd │ │ ├── long01.xml │ │ ├── long02.xml │ │ ├── long03.xml │ │ ├── long04.xml │ │ ├── long05.xml │ │ ├── long_hint01.xml │ │ ├── long_hint02.xml │ │ ├── long_hint03.xml │ │ ├── long_late01.xml │ │ ├── long_late02.xml │ │ ├── long_late03.xml │ │ ├── long_late04.xml │ │ ├── long_late05.xml │ │ ├── medium01.xml │ │ ├── medium02.xml │ │ ├── medium03.xml │ │ ├── medium04.xml │ │ ├── medium05.xml │ │ ├── medium_hint01.xml │ │ ├── medium_hint02.xml │ │ ├── medium_hint03.xml │ │ ├── medium_late01.xml │ │ ├── medium_late02.xml │ │ ├── medium_late03.xml │ │ ├── medium_late04.xml │ │ ├── medium_late05.xml │ │ ├── sprint01.xml │ │ ├── sprint01_1week.xml │ │ ├── sprint02.xml │ │ ├── sprint03.xml │ │ ├── sprint04.xml │ │ ├── sprint05.xml │ │ ├── sprint06.xml │ │ ├── sprint07.xml │ │ ├── sprint08.xml │ │ ├── sprint09.xml │ │ ├── sprint10.xml │ │ ├── sprint_hint01.xml │ │ ├── sprint_hint02.xml │ │ ├── sprint_hint03.xml │ │ ├── sprint_late01.xml │ │ ├── sprint_late02.xml │ │ ├── sprint_late03.xml │ │ ├── sprint_late04.xml │ │ ├── sprint_late05.xml │ │ ├── sprint_late06.xml │ │ ├── sprint_late07.xml │ │ ├── sprint_late08.xml │ │ ├── sprint_late09.xml │ │ ├── sprint_late10.xml │ │ ├── toy1.xml │ │ └── toy2.xml │ │ └── unsolved │ │ ├── long01.xml │ │ ├── long02.xml │ │ ├── long_hint01.xml │ │ ├── long_hint02.xml │ │ ├── medium01.xml │ │ ├── medium02.xml │ │ ├── medium_hint01.xml │ │ ├── medium_hint02.xml │ │ ├── medium_late01_initialized.xml │ │ ├── sprint01.xml │ │ ├── sprint02.xml │ │ ├── sprint_hint01.xml │ │ └── sprint_hint02.xml ├── logback.xml └── planner │ ├── EmployeeRosteringScoreRules.drl │ ├── EmployeeRosteringSolverConfig.xml │ └── planner.xml └── webapp ├── WEB-INF ├── authentication_shiro.properties ├── isis.properties ├── logging.properties ├── persistor.properties ├── persistor_datanucleus.properties ├── shiro.ini ├── translations-en.po ├── translations-es.po ├── translations-nl.po ├── translations.po ├── viewer_restfulobjects.properties ├── viewer_wicket.properties └── web.xml ├── about ├── images │ └── logo.jpg └── index.html ├── css └── application.css ├── images └── spinning-icon.gif ├── scripts └── application.js └── swagger-ui └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | /translations.pot 2 | **/.DS_Store 3 | .DS_Store 4 | target 5 | **/target/ 6 | .idea 7 | *.iml 8 | *.log 9 | **/*.log 10 | **/*.iml 11 | integtests/translations.pot 12 | webapp/logs/sql.log.1 13 | webapp/src/main/resources/data/rotabuilder/solved/ 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tomcat:9.0.2-alpine 2 | MAINTAINER Bilgin Ibryam 3 | EXPOSE 8080 4 | COPY webapp/target/ROOT.war /maven/ROOT.war 5 | RUN rm -fr /usr/local/tomcat/webapps/* && mv /maven/ROOT.war /usr/local/tomcat/webapps/ 6 | RUN chgrp -R 0 /usr/local/tomcat && chmod -R g=u /usr/local/tomcat 7 | CMD catalina.sh run 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Bilgin Ibryam - http://twitter.com/bibryam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### RotaBuilder - Employee Rostering 2 | *A Java web application for nurse scheduling based on [OptaPlanner](http://optaplanner.org/) and [Apache Isis](http://isis.apache.org/)* 3 | 4 | ### (option 1) Local: Build and Run with Maven 5 | 6 | mvn clean install -DskipTests=true 7 | cd webapp 8 | mvn jetty:run 9 | 10 | #### (option 2) Local: Build and Run with Docker 11 | 12 | mvn clean install -DskipTests=true 13 | docker build --rm -t bibryam/rotabuilder . 14 | docker run -p 8080:8080 bibryam/rotabuilder 15 | 16 | #### (option 3) OpenShift Online: Deploy existing Docker image to OpenShift 17 | Create an OpenShift Online [account](https://manage.openshift.com/). Notice, even the free tier account is enough to try out the application. 18 | Install OpenShift client locally (oc) and login to OpenShift. The following commands will run the latest Rotabuilder Docker image and expose its URL to outside world. 19 | 20 | oc new-project rotabuilder 21 | oc new-app bibryam/rotabuilder:latest -e CATALINA_OPTS="-Xmx300m" 22 | oc expose service rotabuilder 23 | 24 | The process takes some time as it has to download the Docker images and there are not much free resources on a free tier account. Notice also we limit Tomcat heap size in order to run in a Docker container with 512MB memory. After few minutes, you should be able to access your Rotabuilder instance. 25 | 26 | ### Login 27 | http://localhost:8080/ 28 | 29 | test:test - no tenancies 30 | user:user - default demo user 31 | admin:admin - admin user 32 | 33 | ### Live Demo on Red Hat OpenShift 34 | 35 | See live demo running at [http://rotabuilder.com](http://rotabuilder.com) 36 | 37 | ### Screenshot 38 | 39 | ![project view](https://2.bp.blogspot.com/-jb-IJWAOtbY/WjUIQ1tRCII/AAAAAAAAJ5Y/83vQxgATqJwC_gh2xsNgEyjAGsYuz9aMgCLcBGAs/s1600/Screen%2BShot%2B2017-12-16%2Bat%2B11.47.33.png) 40 | 41 | 42 | ### Application Features 43 | - Manage employees 44 | - Manage skills 45 | - Manage days on/off requests 46 | - Manage shift on/off requests 47 | - Manage contracts 48 | - Manage shifts 49 | - Create automatic employee-shift assignments 50 | 51 | -------------------------------------------------------------------------------- /app/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | com.rotabuilder 7 | rotabuilder 8 | 1.0-SNAPSHOT 9 | 10 | 11 | app 12 | RotaBuilder App 13 | 14 | 15 | 16 | 17 | src/main/resources 18 | 19 | 20 | src/main/java 21 | 22 | ** 23 | 24 | 25 | **/*.java 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ${project.groupId} 34 | fixture 35 | 36 | 37 | org.apache.isis.core 38 | isis-core-wrapper 39 | 40 | 41 | org.apache.isis.core 42 | isis-core-runtime 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/DomainAppAppManifest.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.app; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import com.google.common.collect.Lists; 9 | import com.google.common.collect.Maps; 10 | import com.rotabuilder.dom.DomainAppDomainModule; 11 | import com.rotabuilder.fixture.DomainAppFixtureModule; 12 | import com.rotabuilder.fixture.scenarios.UserFixture; 13 | import com.rotabuilder.fixture.scenarios.RecreateContracts; 14 | import com.rotabuilder.fixture.scenarios.RecreateEmployees; 15 | import com.rotabuilder.fixture.scenarios.RecreatePatterns; 16 | import com.rotabuilder.fixture.scenarios.RecreateShiftDates; 17 | import com.rotabuilder.fixture.scenarios.RecreateShiftType; 18 | import com.rotabuilder.fixture.scenarios.RecreateSkills; 19 | import org.apache.isis.applib.AppManifest; 20 | import org.apache.isis.applib.fixturescripts.FixtureScript; 21 | import org.isisaddons.module.audit.AuditModule; 22 | import org.isisaddons.module.command.CommandModule; 23 | import org.isisaddons.module.security.SecurityModule; 24 | import org.isisaddons.module.sessionlogger.SessionLoggerModule; 25 | import org.isisaddons.module.settings.SettingsModule; 26 | 27 | /** 28 | * Bootstrap the application. 29 | */ 30 | public class DomainAppAppManifest implements AppManifest { 31 | 32 | /** 33 | * Load all services and entities found in (the packages and subpackages within) these modules 34 | */ 35 | @Override 36 | public List> getModules() { 37 | return Arrays.asList( 38 | DomainAppDomainModule.class, // domain (entities and repositories) 39 | DomainAppFixtureModule.class, // fixtures 40 | DomainAppAppModule.class, // home page service etc 41 | SecurityModule.class, 42 | SessionLoggerModule.class, 43 | AuditModule.class, 44 | SettingsModule.class, 45 | CommandModule.class 46 | ); 47 | } 48 | 49 | @Override 50 | public List> getAdditionalServices() { 51 | return Arrays.asList( 52 | org.isisaddons.module.security.dom.password.PasswordEncryptionServiceUsingJBcrypt.class 53 | ,org.isisaddons.module.security.dom.permission.PermissionsEvaluationServiceAllowBeatsVeto.class 54 | ); 55 | } 56 | 57 | /** 58 | * Use shiro for authentication. 59 | * 60 | *

61 | * NB: this is ignored for integration tests, which always use "bypass". 62 | *

63 | */ 64 | @Override 65 | public String getAuthenticationMechanism() { 66 | return "shiro"; 67 | } 68 | 69 | /** 70 | * Use shiro for authorization. 71 | * 72 | *

73 | * NB: this is ignored for integration tests, which always use "bypass". 74 | *

75 | */ 76 | @Override 77 | public String getAuthorizationMechanism() { 78 | return "shiro"; 79 | } 80 | 81 | /** 82 | * Fixtures to be installed. 83 | */ 84 | @Override 85 | public List> getFixtures() { 86 | return Lists.newArrayList( 87 | UserFixture.class, 88 | RecreateSkills.class, 89 | RecreateShiftType.class, 90 | RecreateShiftDates.class, 91 | RecreatePatterns.class, 92 | RecreateContracts.class, 93 | RecreateEmployees.class); 94 | } 95 | /** 96 | * Force fixtures to be loaded. 97 | */ 98 | @Override 99 | public Map getConfigurationProperties() { 100 | HashMap props = Maps.newHashMap(); 101 | props.put("isis.persistor.datanucleus.install-fixtures","true"); 102 | props.put("isis.reflector.facets.include", "org.isisaddons.module.security.facets.TenantedAuthorizationFacetFactory"); 103 | 104 | return props; 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/DomainAppAppModule.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.app; 2 | 3 | public final class DomainAppAppModule { 4 | private DomainAppAppModule(){} 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/DomainAppTestManifest.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.app; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import com.google.common.collect.Lists; 10 | import com.google.common.collect.Maps; 11 | import com.rotabuilder.dom.DomainAppDomainModule; 12 | import com.rotabuilder.fixture.DomainAppFixtureModule; 13 | import org.apache.isis.applib.AppManifest; 14 | import org.apache.isis.applib.fixturescripts.FixtureScript; 15 | 16 | /** 17 | * Bootstrap the application. 18 | */ 19 | public class DomainAppTestManifest implements AppManifest { 20 | 21 | /** 22 | * Load all services and entities found in (the packages and subpackages within) these modules 23 | */ 24 | @Override 25 | public List> getModules() { 26 | return Arrays.asList( 27 | DomainAppDomainModule.class, // domain (entities and repositories) 28 | DomainAppFixtureModule.class, // fixtures 29 | DomainAppAppModule.class // home page service etc 30 | ); 31 | } 32 | 33 | /** 34 | * No additional services. 35 | */ 36 | @Override 37 | public List> getAdditionalServices() { 38 | return Collections.emptyList(); 39 | } 40 | 41 | /** 42 | * Use shiro for authentication. 43 | * 44 | *

45 | * NB: this is ignored for integration tests, which always use "bypass". 46 | *

47 | */ 48 | @Override 49 | public String getAuthenticationMechanism() { 50 | return "bypass"; 51 | } 52 | 53 | /** 54 | * Use shiro for authorization. 55 | * 56 | *

57 | * NB: this is ignored for integration tests, which always use "bypass". 58 | *

59 | */ 60 | @Override 61 | public String getAuthorizationMechanism() { 62 | return "bypass"; 63 | } 64 | 65 | /** 66 | * Fixtures to be installed. 67 | */ 68 | @Override 69 | public List> getFixtures() { 70 | return Lists.newArrayList(); 71 | } 72 | 73 | /** 74 | * Force fixtures to be loaded. 75 | */ 76 | @Override 77 | public Map getConfigurationProperties() { 78 | HashMap props = Maps.newHashMap(); 79 | props.put("isis.persistor.datanucleus.install-fixtures","true"); 80 | return props; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/services/homepage/HomePageService.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.app.services.homepage; 2 | 3 | import org.apache.isis.applib.annotation.Action; 4 | import org.apache.isis.applib.annotation.DomainService; 5 | import org.apache.isis.applib.annotation.HomePage; 6 | import org.apache.isis.applib.annotation.NatureOfService; 7 | import org.apache.isis.applib.annotation.SemanticsOf; 8 | import org.apache.isis.applib.services.registry.ServiceRegistry; 9 | 10 | // trick to suppress the actions from the top-level menu 11 | @DomainService(nature = NatureOfService.VIEW_CONTRIBUTIONS_ONLY) 12 | public class HomePageService { 13 | 14 | //region > homePage (action) 15 | 16 | @Action(semantics = SemanticsOf.SAFE) 17 | @HomePage 18 | public HomePageViewModel homePage() { 19 | return serviceRegistry.injectServicesInto(new HomePageViewModel()); 20 | } 21 | 22 | //endregion 23 | 24 | //region > injected services 25 | 26 | @javax.inject.Inject 27 | ServiceRegistry serviceRegistry; 28 | 29 | //endregion 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/services/homepage/HomePageViewModel.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.app.services.homepage; 2 | 3 | import java.util.List; 4 | 5 | import com.rotabuilder.dom.domain.employee.Employee; 6 | import com.rotabuilder.dom.domain.employee.EmployeeRepository; 7 | import com.rotabuilder.dom.domain.shift.ShiftAssignment; 8 | import com.rotabuilder.dom.domain.shift.ShiftService; 9 | import org.apache.isis.applib.annotation.Action; 10 | import org.apache.isis.applib.annotation.SemanticsOf; 11 | import org.apache.isis.applib.annotation.ViewModel; 12 | import org.apache.isis.applib.services.i18n.TranslatableString; 13 | import org.apache.isis.applib.services.wrapper.WrapperFactory; 14 | 15 | @ViewModel 16 | public class HomePageViewModel { 17 | 18 | //region > title 19 | public TranslatableString title() { 20 | return TranslatableString.tr("{num} employees", "num", getEmployees().size()); 21 | } 22 | //endregion 23 | 24 | //region > object (collection) 25 | @org.apache.isis.applib.annotation.HomePage 26 | public List getEmployees() { 27 | return wrapperFactory.wrap(employeeRepository).listAll(); 28 | } 29 | 30 | @Action(semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE) 31 | public List startPlanning() { 32 | return shiftService.plan(); 33 | } 34 | 35 | @javax.inject.Inject 36 | EmployeeRepository employeeRepository; 37 | 38 | 39 | @javax.inject.Inject 40 | ShiftService shiftService; 41 | 42 | 43 | @javax.inject.Inject 44 | WrapperFactory wrapperFactory; 45 | 46 | //endregion 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/services/homepage/HomePageViewModel.layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | HomePageViewModel 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/services/homepage/HomePageViewModel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bibryam/rotabuilder/74bf5f1f2ce2b714063eed1e3a6aa63be9c5808e/app/src/main/java/com/rotabuilder/app/services/homepage/HomePageViewModel.png -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/services/registration/AppUserRegistrationService.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.app.services.registration; 2 | 3 | import java.util.Collections; 4 | import java.util.Set; 5 | import javax.inject.Inject; 6 | 7 | import org.apache.isis.applib.annotation.DomainService; 8 | import org.isisaddons.module.security.dom.role.ApplicationRole; 9 | import org.isisaddons.module.security.dom.role.ApplicationRoleRepository; 10 | import org.isisaddons.module.security.userreg.SecurityModuleAppUserRegistrationServiceAbstract; 11 | 12 | @DomainService 13 | public class AppUserRegistrationService extends SecurityModuleAppUserRegistrationServiceAbstract { 14 | protected ApplicationRole getInitialRole() { 15 | return findRole("isis-module-security-regular-user"); 16 | } 17 | protected Set getAdditionalInitialRoles() { 18 | return Collections.singleton(findRole("easter2017")); 19 | } 20 | private ApplicationRole findRole(final String roleName) { 21 | return applicationRoleRepository.findByNameCached(roleName); 22 | } 23 | @Inject 24 | private ApplicationRoleRepository applicationRoleRepository; 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/services/tenancyevaluator/ApplicationTenancyEvaluatorForRoster.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.app.services.tenancyevaluator; 2 | 3 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 4 | import org.apache.isis.applib.annotation.DomainService; 5 | import org.apache.isis.applib.annotation.NatureOfService; 6 | import org.isisaddons.module.security.dom.tenancy.ApplicationTenancy; 7 | import org.isisaddons.module.security.dom.tenancy.ApplicationTenancyEvaluator; 8 | import org.isisaddons.module.security.dom.user.ApplicationUser; 9 | 10 | @DomainService(nature = NatureOfService.DOMAIN) 11 | public class ApplicationTenancyEvaluatorForRoster implements ApplicationTenancyEvaluator { 12 | 13 | @Override 14 | public boolean handles(Class cls) { 15 | return AbstractPersistable.class.isAssignableFrom(cls); 16 | } 17 | 18 | @Override 19 | public String hides(Object domainObject, ApplicationUser applicationUser) { 20 | if (!(domainObject instanceof AbstractPersistable)) { 21 | return null; 22 | } 23 | 24 | final AbstractPersistable persistable = (AbstractPersistable) domainObject; 25 | final ApplicationTenancy applicationUserTenancy = applicationUser.getTenancy(); 26 | final ApplicationTenancy persistableApplicationTenancy = persistable.getApplicationTenancy(); 27 | 28 | if (applicationUserTenancy == null || persistableApplicationTenancy == null) { 29 | return "missing tenancy"; 30 | } 31 | 32 | return applicationUserTenancy.equals(persistableApplicationTenancy) ? null: "different tenancies"; 33 | } 34 | 35 | @Override 36 | public String disables(Object domainObject, ApplicationUser applicationUser) { 37 | return null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/services/tenancyevaluator/TenancySwitcher.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.app.services.tenancyevaluator; 2 | 3 | import java.util.List; 4 | 5 | import com.rotabuilder.app.services.homepage.HomePageService; 6 | import com.rotabuilder.app.services.homepage.HomePageViewModel; 7 | import org.apache.isis.applib.AbstractService; 8 | import org.apache.isis.applib.annotation.Action; 9 | import org.apache.isis.applib.annotation.ActionLayout; 10 | import org.apache.isis.applib.annotation.DomainService; 11 | import org.apache.isis.applib.annotation.DomainServiceLayout; 12 | import org.apache.isis.applib.annotation.NatureOfService; 13 | import org.apache.isis.applib.annotation.SemanticsOf; 14 | import org.isisaddons.module.security.app.user.MeService; 15 | import org.isisaddons.module.security.dom.tenancy.ApplicationTenancy; 16 | import org.isisaddons.module.security.dom.tenancy.ApplicationTenancyRepository; 17 | import org.isisaddons.module.security.dom.user.ApplicationUser; 18 | 19 | @DomainService( 20 | nature = NatureOfService.VIEW_MENU_ONLY 21 | ) 22 | @DomainServiceLayout( 23 | menuBar = DomainServiceLayout.MenuBar.TERTIARY 24 | ) 25 | public class TenancySwitcher extends AbstractService { 26 | 27 | //region > switchTenancy (action) 28 | @Action( 29 | semantics = SemanticsOf.IDEMPOTENT 30 | ) 31 | @ActionLayout( 32 | cssClassFa = "fa-exchange" 33 | ) 34 | public HomePageViewModel switchTenancy(final ApplicationTenancy applicationTenancy) { 35 | final ApplicationUser applicationUser = meService.me(); 36 | applicationUser.updateTenancy(applicationTenancy); 37 | return homePageService.homePage(); 38 | } 39 | 40 | public boolean hideSwitchTenancy() { 41 | final ApplicationUser applicationUser = meService.me(); 42 | return !"admin".equals(applicationUser.getName()); 43 | } 44 | 45 | public List choices0SwitchTenancy() { 46 | return applicationTenancyRepository.allTenancies(); 47 | } 48 | 49 | public ApplicationTenancy default0SwitchTenancy() { 50 | final ApplicationUser applicationUser = meService.me(); 51 | return applicationUser.getTenancy(); 52 | } 53 | //endregion 54 | 55 | //region > injected services 56 | @javax.inject.Inject 57 | private MeService meService; 58 | 59 | @javax.inject.Inject 60 | private ApplicationTenancyRepository applicationTenancyRepository; 61 | 62 | @javax.inject.Inject 63 | private HomePageService homePageService; 64 | //endregion 65 | 66 | } 67 | 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/rotabuilder/app/services/tenancyevaluator/UserProfileServiceShowingTenancy.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.app.services.tenancyevaluator; 2 | 3 | import javax.inject.Inject; 4 | 5 | import org.apache.isis.applib.annotation.DomainService; 6 | import org.apache.isis.applib.annotation.NatureOfService; 7 | import org.apache.isis.applib.annotation.Programmatic; 8 | import org.apache.isis.applib.services.userprof.UserProfileService; 9 | import org.isisaddons.module.security.app.user.MeService; 10 | import org.isisaddons.module.security.dom.tenancy.ApplicationTenancy; 11 | import org.isisaddons.module.security.dom.user.ApplicationUser; 12 | 13 | /** 14 | * Demonstrates how to provide a custom implementation of the {@link UserProfileService}. 15 | */ 16 | @DomainService( 17 | nature = NatureOfService.DOMAIN 18 | ) 19 | public class UserProfileServiceShowingTenancy implements UserProfileService { 20 | 21 | @Override 22 | @Programmatic 23 | public String userProfileName() { 24 | final ApplicationUser applicationUser = meService.me(); 25 | 26 | final StringBuilder buf = new StringBuilder(); 27 | final String username = applicationUser.getName(); 28 | final ApplicationTenancy tenancy = applicationUser.getTenancy(); 29 | 30 | buf.append("Hi "); 31 | buf.append(username); 32 | if (tenancy.getName() != null) { 33 | buf.append(" @").append(tenancy.getName()); 34 | } 35 | 36 | return buf.toString(); 37 | } 38 | 39 | 40 | @Inject 41 | private MeService meService; 42 | } 43 | -------------------------------------------------------------------------------- /dom/log4j.properties: -------------------------------------------------------------------------------- 1 | # LOG4J Configuration 2 | # =================== 3 | 4 | # Basic logging goes to "datanucleus.log" 5 | log4j.appender.A1=org.apache.log4j.FileAppender 6 | log4j.appender.A1.File=datanucleus.log 7 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss,SSS} (%t) %-5p [%c] - %m%n 9 | #log4j.appender.A1.Threshold=INFO 10 | 11 | # Categories 12 | # Each category can be set to a "level", and to direct to an appender 13 | 14 | # Default to DEBUG level for all DataNucleus categories 15 | log4j.logger.DataNucleus = DEBUG, A1 16 | 17 | log4j.category.com.mchange.v2.c3p0=INFO, A1 18 | log4j.category.com.mchange.v2.resourcepool=INFO, A1 19 | log4j.category.org.logicalcobwebs.proxool=INFO,A1 20 | 21 | 22 | # Hbase libs logging 23 | log4j.category.org.apache.hadoop=INFO,A1 24 | log4j.category.org.apache.zookeeper=INFO,A1 -------------------------------------------------------------------------------- /dom/src/main/java/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/DomainAppDomManifest.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.apache.isis.applib.AppManifest; 9 | import org.apache.isis.applib.fixturescripts.FixtureScript; 10 | 11 | /** 12 | * Provided for isis-maven-plugin. 13 | */ 14 | public class DomainAppDomManifest implements AppManifest { 15 | 16 | @Override 17 | public List> getModules() { 18 | return Arrays.>asList( 19 | DomainAppDomainModule.class // domain (entities and repositories) 20 | ); 21 | } 22 | 23 | @Override 24 | public List> getAdditionalServices() { 25 | return Collections.emptyList(); 26 | } 27 | 28 | @Override 29 | public String getAuthenticationMechanism() { 30 | return null; 31 | } 32 | 33 | @Override 34 | public String getAuthorizationMechanism() { 35 | return null; 36 | } 37 | 38 | @Override 39 | public List> getFixtures() { 40 | return null; 41 | } 42 | 43 | /** 44 | * No overrides. 45 | */ 46 | @Override 47 | public Map getConfigurationProperties() { 48 | return null; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/DomainAppDomainModule.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom; 2 | 3 | public final class DomainAppDomainModule { 4 | 5 | 6 | } 7 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/contract/BooleanContractLine.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.contract; 2 | 3 | import javax.jdo.annotations.InheritanceStrategy; 4 | 5 | import com.thoughtworks.xstream.annotations.XStreamAlias; 6 | 7 | @javax.jdo.annotations.PersistenceCapable 8 | @javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.SUPERCLASS_TABLE) 9 | 10 | @XStreamAlias("BooleanContractLine") 11 | public class BooleanContractLine extends ContractLine { 12 | 13 | @javax.jdo.annotations.Column(allowsNull = "false") 14 | private boolean enabled; 15 | 16 | @javax.jdo.annotations.Column(allowsNull = "true") 17 | private int weight; 18 | 19 | public boolean isEnabled() { 20 | return enabled; 21 | } 22 | 23 | public void setEnabled(boolean enabled) { 24 | this.enabled = enabled; 25 | } 26 | 27 | public int getWeight() { 28 | return weight; 29 | } 30 | 31 | public void setWeight(int weight) { 32 | this.weight = weight; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/contract/Contract.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.contract; 2 | 3 | import java.util.List; 4 | import javax.jdo.annotations.IdentityType; 5 | 6 | import com.thoughtworks.xstream.annotations.XStreamAlias; 7 | import com.rotabuilder.dom.domain.pattern.Pattern; 8 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 9 | import com.rotabuilder.dom.domain.pattern.WeekendDefinition; 10 | import org.apache.isis.applib.annotation.DomainObject; 11 | 12 | @javax.jdo.annotations.PersistenceCapable( 13 | identityType= IdentityType.DATASTORE, 14 | schema = "simple" 15 | ) 16 | @DomainObject( 17 | autoCompleteRepository = ContractRepository.class, 18 | autoCompleteAction = "autoComplete") 19 | @XStreamAlias("Contract") 20 | public class Contract extends AbstractPersistable { 21 | 22 | @javax.jdo.annotations.Column(allowsNull = "false") 23 | private String code; 24 | 25 | @javax.jdo.annotations.Column(allowsNull = "false") 26 | private String description; 27 | 28 | @javax.jdo.annotations.Column(allowsNull = "false") 29 | private WeekendDefinition weekendDefinition; 30 | 31 | private List contractLineList; 32 | 33 | private List patternList; 34 | 35 | @javax.jdo.annotations.Persistent() 36 | public List getPatternList() { 37 | return patternList; 38 | } 39 | 40 | public void setPatternList(List patternList) { 41 | this.patternList = patternList; 42 | } 43 | 44 | public String getCode() { 45 | return code; 46 | } 47 | 48 | public void setCode(String code) { 49 | this.code = code; 50 | } 51 | 52 | public String getDescription() { 53 | return description; 54 | } 55 | 56 | public void setDescription(String description) { 57 | this.description = description; 58 | } 59 | 60 | public WeekendDefinition getWeekendDefinition() { 61 | return weekendDefinition; 62 | } 63 | 64 | public void setWeekendDefinition(WeekendDefinition weekendDefinition) { 65 | this.weekendDefinition = weekendDefinition; 66 | } 67 | 68 | @javax.jdo.annotations.Persistent(mappedBy = "contract", defaultFetchGroup = "true") 69 | public List getContractLineList() { 70 | return contractLineList; 71 | } 72 | 73 | public void setContractLineList(List contractLineList) { 74 | this.contractLineList = contractLineList; 75 | } 76 | 77 | @Override 78 | public String toString() { 79 | return code; 80 | } 81 | 82 | public int getWeekendLength() { 83 | return weekendDefinition.getWeekendLength(); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/contract/Contract.layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/contract/ContractLine.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.contract; 2 | 3 | import javax.jdo.annotations.DiscriminatorStrategy; 4 | import javax.jdo.annotations.IdentityType; 5 | import javax.jdo.annotations.InheritanceStrategy; 6 | 7 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 8 | import com.thoughtworks.xstream.annotations.XStreamAlias; 9 | import com.thoughtworks.xstream.annotations.XStreamInclude; 10 | 11 | @XStreamAlias("ContractLine") 12 | @XStreamInclude({ 13 | BooleanContractLine.class, 14 | MinMaxContractLine.class 15 | }) 16 | @javax.jdo.annotations.PersistenceCapable( 17 | identityType= IdentityType.DATASTORE, 18 | schema = "simple" 19 | ) 20 | @javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.NEW_TABLE) 21 | @javax.jdo.annotations.Discriminator( 22 | strategy = DiscriminatorStrategy.CLASS_NAME, 23 | column = "discriminator") 24 | public abstract class ContractLine extends AbstractPersistable { 25 | 26 | private Contract contract; 27 | 28 | @javax.jdo.annotations.Column(name = "leaseId", allowsNull = "false") 29 | public Contract getContract() { 30 | return contract; 31 | } 32 | 33 | public void setContract(Contract contract) { 34 | this.contract = contract; 35 | } 36 | 37 | @javax.jdo.annotations.Column(allowsNull = "false") 38 | private ContractLineType contractLineType; 39 | 40 | 41 | public ContractLineType getContractLineType() { 42 | return contractLineType; 43 | } 44 | 45 | public void setContractLineType(ContractLineType contractLineType) { 46 | this.contractLineType = contractLineType; 47 | } 48 | 49 | public abstract boolean isEnabled(); 50 | 51 | @Override 52 | public String toString() { 53 | return contractLineType.toString(); 54 | } 55 | 56 | @javax.inject.Inject 57 | ContractRepository contractRepository; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/contract/ContractLineType.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.contract; 2 | 3 | public enum ContractLineType { 4 | SINGLE_ASSIGNMENT_PER_DAY, 5 | TOTAL_ASSIGNMENTS, 6 | CONSECUTIVE_WORKING_DAYS, 7 | CONSECUTIVE_FREE_DAYS, 8 | CONSECUTIVE_WORKING_WEEKENDS, 9 | TOTAL_WORKING_WEEKENDS_IN_FOUR_WEEKS, 10 | COMPLETE_WEEKENDS, 11 | IDENTICAL_SHIFT_TYPES_DURING_WEEKEND, 12 | NO_NIGHT_SHIFT_BEFORE_FREE_WEEKEND, 13 | ALTERNATIVE_SKILL_CATEGORY 14 | } 15 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/contract/ContractRepository.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.contract; 2 | 3 | import java.util.List; 4 | 5 | import com.rotabuilder.dom.domain.pattern.WeekendDefinition; 6 | import org.apache.isis.applib.annotation.DomainService; 7 | import org.apache.isis.applib.annotation.NatureOfService; 8 | import org.apache.isis.applib.annotation.Programmatic; 9 | import org.apache.isis.applib.services.registry.ServiceRegistry2; 10 | import org.apache.isis.applib.services.repository.RepositoryService; 11 | 12 | @DomainService( 13 | nature = NatureOfService.DOMAIN, 14 | repositoryFor = Contract.class 15 | ) 16 | public class ContractRepository { 17 | 18 | @javax.inject.Inject 19 | RepositoryService repositoryService; 20 | 21 | @javax.inject.Inject 22 | ServiceRegistry2 serviceRegistry; 23 | 24 | public List listAll() { 25 | return repositoryService.allInstances(Contract.class); 26 | } 27 | 28 | public Contract create(String code, String description, WeekendDefinition weekendDefinition 29 | ) { 30 | final Contract object = new Contract(); 31 | object.setCode(code); 32 | object.setDescription(description); 33 | object.setWeekendDefinition(weekendDefinition); 34 | 35 | serviceRegistry.injectServicesInto(object); 36 | object.init(); 37 | repositoryService.persist(object); 38 | return object; 39 | } 40 | 41 | @Programmatic 42 | public List autoComplete(final String description) { 43 | return repositoryService.allInstances(Contract.class); 44 | } 45 | 46 | 47 | public List listBooleanContractLineS() { 48 | return repositoryService.allInstances(BooleanContractLine.class); 49 | } 50 | 51 | public BooleanContractLine createBooleanContractLine(Contract contract, ContractLineType contractLineType, boolean enabled, int weight) { 52 | final BooleanContractLine object = new BooleanContractLine(); 53 | object.setContract(contract); 54 | object.setContractLineType(contractLineType); 55 | object.setEnabled(enabled); 56 | object.setWeight(weight); 57 | 58 | serviceRegistry.injectServicesInto(object); 59 | object.init(); 60 | repositoryService.persist(object); 61 | return object; 62 | } 63 | 64 | 65 | public List listMinMaxContractLines() { 66 | return repositoryService.allInstances(MinMaxContractLine.class); 67 | } 68 | 69 | public MinMaxContractLine createMinMaxContractLine(Contract contract, ContractLineType contractLineType, 70 | boolean minimumEnabled, 71 | int minimumValue, 72 | int minimumWeight, 73 | boolean maximumEnabled, 74 | int maximumValue, 75 | int maximumWeight) { 76 | final MinMaxContractLine object = new MinMaxContractLine(); 77 | object.setContract(contract); 78 | object.setContractLineType(contractLineType); 79 | object.setMinimumEnabled(minimumEnabled); 80 | object.setMinimumValue(minimumValue); 81 | object.setMinimumWeight(minimumWeight); 82 | object.setMaximumEnabled(maximumEnabled); 83 | object.setMaximumValue(maximumValue); 84 | object.setMaximumWeight(maximumWeight); 85 | 86 | serviceRegistry.injectServicesInto(object); 87 | object.init(); 88 | repositoryService.persist(object); 89 | return object; 90 | } 91 | 92 | 93 | 94 | } 95 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/contract/MinMaxContractLine.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.contract; 2 | 3 | import javax.jdo.annotations.InheritanceStrategy; 4 | 5 | import com.thoughtworks.xstream.annotations.XStreamAlias; 6 | 7 | @javax.jdo.annotations.PersistenceCapable 8 | @javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.SUPERCLASS_TABLE) 9 | 10 | @XStreamAlias("MinMaxContractLine") 11 | public class MinMaxContractLine extends ContractLine { 12 | 13 | @javax.jdo.annotations.Column(allowsNull = "false") 14 | private boolean minimumEnabled; 15 | 16 | @javax.jdo.annotations.Column(allowsNull = "true") 17 | private int minimumValue; 18 | 19 | @javax.jdo.annotations.Column(allowsNull = "true") 20 | private int minimumWeight; 21 | 22 | @javax.jdo.annotations.Column(allowsNull = "false") 23 | private boolean maximumEnabled; 24 | 25 | @javax.jdo.annotations.Column(allowsNull = "true") 26 | private int maximumValue; 27 | 28 | @javax.jdo.annotations.Column(allowsNull = "true") 29 | private int maximumWeight; 30 | 31 | public boolean isMinimumEnabled() { 32 | return minimumEnabled; 33 | } 34 | 35 | public void setMinimumEnabled(boolean minimumEnabled) { 36 | this.minimumEnabled = minimumEnabled; 37 | } 38 | 39 | public int getMinimumValue() { 40 | return minimumValue; 41 | } 42 | 43 | public void setMinimumValue(int minimumValue) { 44 | this.minimumValue = minimumValue; 45 | } 46 | 47 | public int getMinimumWeight() { 48 | return minimumWeight; 49 | } 50 | 51 | public void setMinimumWeight(int minimumWeight) { 52 | this.minimumWeight = minimumWeight; 53 | } 54 | 55 | public boolean isMaximumEnabled() { 56 | return maximumEnabled; 57 | } 58 | 59 | public void setMaximumEnabled(boolean maximumEnabled) { 60 | this.maximumEnabled = maximumEnabled; 61 | } 62 | 63 | public int getMaximumValue() { 64 | return maximumValue; 65 | } 66 | 67 | public void setMaximumValue(int maximumValue) { 68 | this.maximumValue = maximumValue; 69 | } 70 | 71 | public int getMaximumWeight() { 72 | return maximumWeight; 73 | } 74 | 75 | public void setMaximumWeight(int maximumWeight) { 76 | this.maximumWeight = maximumWeight; 77 | } 78 | 79 | public boolean isEnabled() { 80 | return minimumEnabled || maximumEnabled; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/contract/PatternContractLine.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.contract; 2 | 3 | import com.rotabuilder.dom.domain.pattern.Pattern; 4 | import com.thoughtworks.xstream.annotations.XStreamAlias; 5 | 6 | @XStreamAlias("PatternContractLine") 7 | public class PatternContractLine { 8 | 9 | private Contract contract; 10 | 11 | private Pattern pattern; 12 | 13 | public Contract getContract() { 14 | return contract; 15 | } 16 | 17 | public void setContract(Contract contract) { 18 | this.contract = contract; 19 | } 20 | 21 | public Pattern getPattern() { 22 | return pattern; 23 | } 24 | 25 | public void setPattern(Pattern pattern) { 26 | this.pattern = pattern; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return contract + "-" + pattern; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/employee/DayOffRequest.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.employee; 2 | 3 | import javax.jdo.annotations.IdentityType; 4 | 5 | import com.rotabuilder.dom.domain.shift.ShiftDate; 6 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 7 | import com.thoughtworks.xstream.annotations.XStreamAlias; 8 | 9 | @javax.jdo.annotations.PersistenceCapable( 10 | identityType= IdentityType.DATASTORE, 11 | schema = "simple" 12 | ) 13 | @XStreamAlias("DayOffRequest") 14 | public class DayOffRequest extends AbstractPersistable { 15 | 16 | @javax.jdo.annotations.Column(allowsNull = "false") 17 | private Employee employee; 18 | 19 | @javax.jdo.annotations.Column(allowsNull = "false") 20 | private ShiftDate shiftDate; 21 | 22 | @javax.jdo.annotations.Column(allowsNull = "false") 23 | private int weight; 24 | 25 | public Employee getEmployee() { 26 | return employee; 27 | } 28 | 29 | public void setEmployee(Employee employee) { 30 | this.employee = employee; 31 | } 32 | 33 | public ShiftDate getShiftDate() { 34 | return shiftDate; 35 | } 36 | 37 | public void setShiftDate(ShiftDate shiftDate) { 38 | this.shiftDate = shiftDate; 39 | } 40 | 41 | public int getWeight() { 42 | return weight; 43 | } 44 | 45 | public void setWeight(int weight) { 46 | this.weight = weight; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return shiftDate + "_OFF_" + employee; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/employee/DayOnRequest.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.employee; 2 | 3 | import javax.jdo.annotations.IdentityType; 4 | 5 | import com.rotabuilder.dom.domain.shift.ShiftDate; 6 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 7 | import com.thoughtworks.xstream.annotations.XStreamAlias; 8 | 9 | @javax.jdo.annotations.PersistenceCapable( 10 | identityType= IdentityType.DATASTORE, 11 | schema = "simple" 12 | ) 13 | @XStreamAlias("DayOnRequest") 14 | public class DayOnRequest extends AbstractPersistable { 15 | 16 | @javax.jdo.annotations.Column(allowsNull = "false") 17 | private Employee employee; 18 | 19 | @javax.jdo.annotations.Column(allowsNull = "false") 20 | private ShiftDate shiftDate; 21 | 22 | @javax.jdo.annotations.Column(allowsNull = "false") 23 | private int weight; 24 | 25 | public Employee getEmployee() { 26 | return employee; 27 | } 28 | 29 | public void setEmployee(Employee employee) { 30 | this.employee = employee; 31 | } 32 | 33 | public ShiftDate getShiftDate() { 34 | return shiftDate; 35 | } 36 | 37 | public void setShiftDate(ShiftDate shiftDate) { 38 | this.shiftDate = shiftDate; 39 | } 40 | 41 | public int getWeight() { 42 | return weight; 43 | } 44 | 45 | public void setWeight(int weight) { 46 | this.weight = weight; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return shiftDate + "_ON_" + employee; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/employee/Employee.layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/employee/Employee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bibryam/rotabuilder/74bf5f1f2ce2b714063eed1e3a6aa63be9c5808e/dom/src/main/java/com/rotabuilder/dom/domain/employee/Employee.png -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/employee/EmployeeMenu.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.employee; 2 | 3 | import java.util.List; 4 | 5 | import com.rotabuilder.dom.domain.contract.Contract; 6 | import org.apache.isis.applib.annotation.Action; 7 | import org.apache.isis.applib.annotation.ActionLayout; 8 | import org.apache.isis.applib.annotation.BookmarkPolicy; 9 | import org.apache.isis.applib.annotation.DomainService; 10 | import org.apache.isis.applib.annotation.DomainServiceLayout; 11 | import org.apache.isis.applib.annotation.MemberOrder; 12 | import org.apache.isis.applib.annotation.NatureOfService; 13 | import org.apache.isis.applib.annotation.ParameterLayout; 14 | import org.apache.isis.applib.annotation.SemanticsOf; 15 | import org.apache.isis.applib.services.eventbus.ActionDomainEvent; 16 | 17 | @DomainService( 18 | nature = NatureOfService.VIEW_MENU_ONLY, 19 | repositoryFor = Employee.class 20 | ) 21 | @DomainServiceLayout( 22 | named = "Employees", 23 | menuOrder = "20" 24 | ) 25 | public class EmployeeMenu { 26 | @Action(semantics = SemanticsOf.SAFE) 27 | @ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT) 28 | @MemberOrder(sequence = "1") 29 | public List listAll() { 30 | return employeeRepository.listAll(); 31 | } 32 | 33 | 34 | @Action(semantics = SemanticsOf.SAFE) 35 | @ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT) 36 | @MemberOrder(sequence = "2") 37 | public List findByName( 38 | @ParameterLayout(named="Name") 39 | final String name 40 | ) { 41 | return employeeRepository.findByName(name); 42 | } 43 | 44 | public static class CreateDomainEvent extends ActionDomainEvent {} 45 | @Action(domainEvent = CreateDomainEvent.class) 46 | @MemberOrder(sequence = "3") 47 | public Employee create( 48 | @ParameterLayout(named="Name") 49 | final String name, 50 | @ParameterLayout(named="Code") 51 | final String code, 52 | @ParameterLayout(named="Contract") 53 | final Contract contract) { 54 | return employeeRepository.create(name, code, contract); 55 | } 56 | 57 | @Action(semantics = SemanticsOf.SAFE) 58 | @ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT) 59 | @MemberOrder(sequence = "4") 60 | public List listSkills() { 61 | return employeeRepository.listSkills(); 62 | } 63 | 64 | @Action(domainEvent = CreateDomainEvent.class) 65 | @MemberOrder(sequence = "5") 66 | public Skill createSkill( 67 | @ParameterLayout(named="Code") 68 | final String code) { 69 | return employeeRepository.createSkill(code); 70 | } 71 | 72 | 73 | @Action(semantics = SemanticsOf.SAFE) 74 | @ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT) 75 | @MemberOrder(sequence = "6") 76 | public List listDayOffRequests() { 77 | return employeeRepository.listDayOffRequests(); 78 | } 79 | 80 | 81 | @Action(semantics = SemanticsOf.SAFE) 82 | @ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT) 83 | @MemberOrder(sequence = "7") 84 | public List listDayOnRequests() { 85 | return employeeRepository.listDayOnRequests(); 86 | } 87 | 88 | @Action(semantics = SemanticsOf.SAFE) 89 | @ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT) 90 | @MemberOrder(sequence = "8") 91 | public List listShiftOnRequests() { 92 | return employeeRepository.listShiftOnRequests(); 93 | } 94 | 95 | @Action(semantics = SemanticsOf.SAFE) 96 | @ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT) 97 | @MemberOrder(sequence = "9") 98 | public List listShiftOffRequests() { 99 | return employeeRepository.listShiftOffRequests(); 100 | } 101 | 102 | @javax.inject.Inject 103 | EmployeeRepository employeeRepository; 104 | 105 | } 106 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/employee/ShiftOffRequest.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.employee; 2 | 3 | import javax.jdo.annotations.IdentityType; 4 | 5 | import com.thoughtworks.xstream.annotations.XStreamAlias; 6 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 7 | import com.rotabuilder.dom.domain.shift.Shift; 8 | 9 | @javax.jdo.annotations.PersistenceCapable( 10 | identityType= IdentityType.DATASTORE, 11 | schema = "simple" 12 | ) 13 | @XStreamAlias("ShiftOffRequest") 14 | public class ShiftOffRequest extends AbstractPersistable { 15 | 16 | @javax.jdo.annotations.Column(allowsNull = "false") 17 | private Employee employee; 18 | 19 | @javax.jdo.annotations.Column(allowsNull = "false") 20 | private Shift shift; 21 | 22 | @javax.jdo.annotations.Column(allowsNull = "false") 23 | private int weight; 24 | 25 | public Employee getEmployee() { 26 | return employee; 27 | } 28 | 29 | public void setEmployee(Employee employee) { 30 | this.employee = employee; 31 | } 32 | 33 | public Shift getShift() { 34 | return shift; 35 | } 36 | 37 | public void setShift(Shift shift) { 38 | this.shift = shift; 39 | } 40 | 41 | public int getWeight() { 42 | return weight; 43 | } 44 | 45 | public void setWeight(int weight) { 46 | this.weight = weight; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return shift + "_OFF_" + employee; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/employee/ShiftOnRequest.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.employee; 2 | 3 | import javax.jdo.annotations.IdentityType; 4 | 5 | import com.rotabuilder.dom.domain.shift.Shift; 6 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 7 | import com.thoughtworks.xstream.annotations.XStreamAlias; 8 | 9 | @javax.jdo.annotations.PersistenceCapable( 10 | identityType= IdentityType.DATASTORE, 11 | schema = "simple" 12 | ) 13 | @XStreamAlias("ShiftOnRequest") 14 | public class ShiftOnRequest extends AbstractPersistable { 15 | 16 | @javax.jdo.annotations.Column(allowsNull = "false") 17 | private Employee employee; 18 | 19 | @javax.jdo.annotations.Column(allowsNull = "false") 20 | private Shift shift; 21 | 22 | @javax.jdo.annotations.Column(allowsNull = "false") 23 | private int weight; 24 | 25 | public Employee getEmployee() { 26 | return employee; 27 | } 28 | 29 | public void setEmployee(Employee employee) { 30 | this.employee = employee; 31 | } 32 | 33 | public Shift getShift() { 34 | return shift; 35 | } 36 | 37 | public void setShift(Shift shift) { 38 | this.shift = shift; 39 | } 40 | 41 | public int getWeight() { 42 | return weight; 43 | } 44 | 45 | public void setWeight(int weight) { 46 | this.weight = weight; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return shift + "_ON_" + employee; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/employee/Skill.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.employee; 2 | 3 | import javax.jdo.annotations.IdentityType; 4 | 5 | import com.thoughtworks.xstream.annotations.XStreamAlias; 6 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 7 | import org.apache.commons.lang3.builder.CompareToBuilder; 8 | import org.apache.isis.applib.annotation.DomainObject; 9 | 10 | @javax.jdo.annotations.PersistenceCapable( 11 | identityType= IdentityType.DATASTORE, 12 | schema = "simple" 13 | ) 14 | @javax.jdo.annotations.Queries({ 15 | @javax.jdo.annotations.Query( 16 | name = "findByName", language = "JDOQL", 17 | value = "SELECT " 18 | + "FROM Skill " 19 | + "WHERE code.indexOf(:code) >= 0 ") 20 | }) 21 | @DomainObject( 22 | autoCompleteRepository = EmployeeRepository.class, 23 | autoCompleteAction = "findSkillsByName") 24 | @XStreamAlias("Skill") 25 | public class Skill extends AbstractPersistable { 26 | 27 | @javax.jdo.annotations.Column(allowsNull = "false") 28 | private String code; 29 | 30 | public String getCode() { 31 | return code; 32 | } 33 | 34 | public void setCode(String code) { 35 | this.code = code; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return code; 41 | } 42 | 43 | public int compareTo(Skill other) { 44 | return new CompareToBuilder() 45 | .append(this.getClass().getName(), other.getClass().getName()) 46 | .append(code, other.code) 47 | .toComparison(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/employee/SkillProficiency.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.employee; 2 | 3 | import com.thoughtworks.xstream.annotations.XStreamAlias; 4 | 5 | @XStreamAlias("SkillProficiency") 6 | public class SkillProficiency { 7 | 8 | private Employee employee; 9 | 10 | private Skill skill; 11 | 12 | public Employee getEmployee() { 13 | return employee; 14 | } 15 | 16 | public void setEmployee(Employee employee) { 17 | this.employee = employee; 18 | } 19 | 20 | public Skill getSkill() { 21 | return skill; 22 | } 23 | 24 | public void setSkill(Skill skill) { 25 | this.skill = skill; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return employee + "-" + skill; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/pattern/DayOfWeek.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.pattern; 2 | 3 | import java.util.Calendar; 4 | 5 | public enum DayOfWeek { 6 | MONDAY("Monday"), 7 | TUESDAY("Tuesday"), 8 | WEDNESDAY("Wednesday"), 9 | THURSDAY("Thursday"), 10 | FRIDAY("Friday"), 11 | SATURDAY("Saturday"), 12 | SUNDAY("Sunday"); 13 | 14 | public static DayOfWeek valueOfCalendar(int calendarDayInWeek) { 15 | switch (calendarDayInWeek) { 16 | case Calendar.SUNDAY: 17 | return SUNDAY; 18 | case Calendar.MONDAY: 19 | return MONDAY; 20 | case Calendar.TUESDAY: 21 | return TUESDAY; 22 | case Calendar.WEDNESDAY: 23 | return WEDNESDAY; 24 | case Calendar.THURSDAY: 25 | return THURSDAY; 26 | case Calendar.FRIDAY: 27 | return FRIDAY; 28 | case Calendar.SATURDAY: 29 | return SATURDAY; 30 | default: 31 | throw new IllegalArgumentException("The calendarDayInWeek (" + calendarDayInWeek 32 | + ") is not supported."); 33 | } 34 | } 35 | 36 | public static DayOfWeek valueOfCode(String code) { 37 | for (DayOfWeek dayOfWeek : values()) { 38 | if (code.equalsIgnoreCase(dayOfWeek.getCode())) { 39 | return dayOfWeek; 40 | } 41 | } 42 | return null; 43 | } 44 | 45 | private String code; 46 | 47 | private DayOfWeek(String code) { 48 | this.code = code; 49 | } 50 | 51 | public String getCode() { 52 | return code; 53 | } 54 | 55 | public int getDistanceToNext(DayOfWeek other) { 56 | int distance = other.ordinal() - ordinal(); 57 | if (distance < 0) { 58 | distance += 7; 59 | } 60 | return distance; 61 | } 62 | 63 | public DayOfWeek determineNextDayOfWeek() { 64 | switch (this) { 65 | case MONDAY: 66 | return TUESDAY; 67 | case TUESDAY: 68 | return WEDNESDAY; 69 | case WEDNESDAY: 70 | return THURSDAY; 71 | case THURSDAY: 72 | return FRIDAY; 73 | case FRIDAY: 74 | return SATURDAY; 75 | case SATURDAY: 76 | return SUNDAY; 77 | case SUNDAY: 78 | return MONDAY; 79 | default: 80 | throw new IllegalArgumentException("The dayOfWeek (" + this + ") is not supported."); 81 | } 82 | } 83 | 84 | public String getLabel() { 85 | return code.substring(0, 2); 86 | } 87 | 88 | public String toString() { 89 | return code.substring(0, 3); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/pattern/FreeBefore2DaysWithAWorkDayPattern.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.pattern; 2 | 3 | import javax.jdo.annotations.InheritanceStrategy; 4 | 5 | import com.thoughtworks.xstream.annotations.XStreamAlias; 6 | 7 | @javax.jdo.annotations.PersistenceCapable 8 | @javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.SUPERCLASS_TABLE) 9 | 10 | @XStreamAlias("FreeBefore2DaysWithAWorkDayPattern") 11 | public class FreeBefore2DaysWithAWorkDayPattern extends Pattern { 12 | 13 | @javax.jdo.annotations.Column(allowsNull = "false") 14 | private DayOfWeek freeDayOfWeek; 15 | 16 | public DayOfWeek getFreeDayOfWeek() { 17 | return freeDayOfWeek; 18 | } 19 | 20 | public void setFreeDayOfWeek(DayOfWeek freeDayOfWeek) { 21 | this.freeDayOfWeek = freeDayOfWeek; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return "Free on " + freeDayOfWeek + " followed by a work day within 2 days"; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/pattern/Pattern.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.pattern; 2 | 3 | import javax.jdo.annotations.DiscriminatorStrategy; 4 | import javax.jdo.annotations.IdentityType; 5 | import javax.jdo.annotations.InheritanceStrategy; 6 | 7 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 8 | import com.thoughtworks.xstream.annotations.XStreamAlias; 9 | import com.thoughtworks.xstream.annotations.XStreamInclude; 10 | 11 | @javax.jdo.annotations.PersistenceCapable( 12 | identityType= IdentityType.DATASTORE, 13 | schema = "simple" 14 | ) 15 | 16 | @javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.NEW_TABLE) 17 | @javax.jdo.annotations.Discriminator( 18 | strategy = DiscriminatorStrategy.CLASS_NAME, 19 | column = "discriminator") 20 | 21 | @XStreamAlias("Pattern") 22 | @XStreamInclude({ 23 | ShiftType2DaysPattern.class, 24 | ShiftType3DaysPattern.class, 25 | WorkBeforeFreeSequencePattern.class, 26 | FreeBefore2DaysWithAWorkDayPattern.class 27 | }) 28 | public abstract class Pattern extends AbstractPersistable { 29 | 30 | @javax.jdo.annotations.Column(allowsNull = "false") 31 | protected String code; 32 | 33 | @javax.jdo.annotations.Column(allowsNull = "false") 34 | protected int weight; 35 | 36 | public String getCode() { 37 | return code; 38 | } 39 | 40 | public void setCode(String code) { 41 | this.code = code; 42 | } 43 | 44 | public int getWeight() { 45 | return weight; 46 | } 47 | 48 | public void setWeight(int weight) { 49 | this.weight = weight; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return code; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/pattern/PatternsRepository.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.pattern; 2 | 3 | import java.util.List; 4 | 5 | import com.rotabuilder.dom.domain.shift.ShiftType; 6 | import org.apache.isis.applib.annotation.DomainService; 7 | import org.apache.isis.applib.annotation.NatureOfService; 8 | import org.apache.isis.applib.services.registry.ServiceRegistry2; 9 | import org.apache.isis.applib.services.repository.RepositoryService; 10 | 11 | @DomainService( 12 | nature = NatureOfService.DOMAIN, 13 | repositoryFor = Pattern.class 14 | ) 15 | public class PatternsRepository { 16 | 17 | @javax.inject.Inject 18 | RepositoryService repositoryService; 19 | 20 | @javax.inject.Inject 21 | ServiceRegistry2 serviceRegistry; 22 | 23 | public List listAll() { 24 | return repositoryService.allInstances(Pattern.class); 25 | } 26 | 27 | public List listFreeBefore2DaysWithAWorkDayPatterns() { 28 | return repositoryService.allInstances(FreeBefore2DaysWithAWorkDayPattern.class); 29 | } 30 | 31 | public List listShiftType2DaysPatterns() { 32 | return repositoryService.allInstances(ShiftType2DaysPattern.class); 33 | } 34 | 35 | public List listShiftType3DaysPatterns() { 36 | return repositoryService.allInstances(ShiftType3DaysPattern.class); 37 | } 38 | 39 | public List listWorkBeforeFreeSequencePatterns() { 40 | return repositoryService.allInstances(WorkBeforeFreeSequencePattern.class); 41 | } 42 | 43 | public FreeBefore2DaysWithAWorkDayPattern createFreeBefore2DaysWithAWorkDayPattern(String code, int weight, DayOfWeek dayOfWeek) { 44 | final FreeBefore2DaysWithAWorkDayPattern object = new FreeBefore2DaysWithAWorkDayPattern(); 45 | object.setCode(code); 46 | object.setWeight(weight); 47 | object.setFreeDayOfWeek(dayOfWeek); 48 | 49 | serviceRegistry.injectServicesInto(object); 50 | object.init(); 51 | repositoryService.persist(object); 52 | return object; 53 | } 54 | 55 | public ShiftType2DaysPattern createShiftType2DaysPattern(String code, int weight, ShiftType shiftTypeOne, ShiftType shiftTypeTwo) { 56 | final ShiftType2DaysPattern object = new ShiftType2DaysPattern(); 57 | object.setCode(code); 58 | object.setWeight(weight); 59 | object.setDayIndex0ShiftType(shiftTypeOne); 60 | object.setDayIndex1ShiftType(shiftTypeTwo); 61 | 62 | serviceRegistry.injectServicesInto(object); 63 | object.init(); 64 | repositoryService.persist(object); 65 | return object; 66 | } 67 | 68 | public ShiftType3DaysPattern createShiftType3DaysPattern(String code, int weight, ShiftType shiftTypeOne, ShiftType shiftTypeTwo, ShiftType shiftTypeThree) { 69 | final ShiftType3DaysPattern object = new ShiftType3DaysPattern(); 70 | object.setCode(code); 71 | object.setWeight(weight); 72 | object.setDayIndex0ShiftType(shiftTypeOne); 73 | object.setDayIndex1ShiftType(shiftTypeTwo); 74 | object.setDayIndex2ShiftType(shiftTypeThree); 75 | 76 | serviceRegistry.injectServicesInto(object); 77 | object.init(); 78 | repositoryService.persist(object); 79 | return object; 80 | } 81 | 82 | public WorkBeforeFreeSequencePattern createWorkBeforeFreeSequencePattern(String code, int weight, ShiftType shiftType, DayOfWeek dayOfWeek, int freeDayLength) { 83 | final WorkBeforeFreeSequencePattern object = new WorkBeforeFreeSequencePattern(); 84 | object.setCode(code); 85 | object.setWeight(weight); 86 | object.setWorkShiftType(shiftType); 87 | object.setWorkDayOfWeek(dayOfWeek); 88 | object.setFreeDayLength(freeDayLength); 89 | 90 | serviceRegistry.injectServicesInto(object); 91 | object.init(); 92 | repositoryService.persist(object); 93 | return object; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/pattern/ShiftType2DaysPattern.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.pattern; 2 | 3 | import javax.jdo.annotations.InheritanceStrategy; 4 | 5 | import com.thoughtworks.xstream.annotations.XStreamAlias; 6 | import com.rotabuilder.dom.domain.shift.ShiftType; 7 | 8 | @javax.jdo.annotations.PersistenceCapable 9 | @javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.SUPERCLASS_TABLE) 10 | 11 | @XStreamAlias("ShiftType2DaysPattern") 12 | public class ShiftType2DaysPattern extends Pattern { 13 | 14 | @javax.jdo.annotations.Column(allowsNull = "false") 15 | private ShiftType dayIndex0ShiftType; 16 | 17 | @javax.jdo.annotations.Column(allowsNull = "false") 18 | private ShiftType dayIndex1ShiftType; 19 | 20 | public ShiftType getDayIndex0ShiftType() { 21 | return dayIndex0ShiftType; 22 | } 23 | 24 | public void setDayIndex0ShiftType(ShiftType dayIndex0ShiftType) { 25 | this.dayIndex0ShiftType = dayIndex0ShiftType; 26 | } 27 | 28 | public ShiftType getDayIndex1ShiftType() { 29 | return dayIndex1ShiftType; 30 | } 31 | 32 | public void setDayIndex1ShiftType(ShiftType dayIndex1ShiftType) { 33 | this.dayIndex1ShiftType = dayIndex1ShiftType; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "Work pattern: " + dayIndex0ShiftType + ", " + dayIndex1ShiftType; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/pattern/ShiftType3DaysPattern.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.pattern; 2 | 3 | import javax.jdo.annotations.InheritanceStrategy; 4 | 5 | import com.thoughtworks.xstream.annotations.XStreamAlias; 6 | import com.rotabuilder.dom.domain.shift.ShiftType; 7 | 8 | @javax.jdo.annotations.PersistenceCapable 9 | @javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.SUPERCLASS_TABLE) 10 | 11 | @XStreamAlias("ShiftType3DaysPattern") 12 | public class ShiftType3DaysPattern extends Pattern { 13 | 14 | @javax.jdo.annotations.Column(allowsNull = "false") 15 | private ShiftType dayIndex0ShiftType; 16 | 17 | @javax.jdo.annotations.Column(allowsNull = "false") 18 | private ShiftType dayIndex1ShiftType; 19 | 20 | @javax.jdo.annotations.Column(allowsNull = "false") 21 | private ShiftType dayIndex2ShiftType; 22 | 23 | public ShiftType getDayIndex0ShiftType() { 24 | return dayIndex0ShiftType; 25 | } 26 | 27 | public void setDayIndex0ShiftType(ShiftType dayIndex0ShiftType) { 28 | this.dayIndex0ShiftType = dayIndex0ShiftType; 29 | } 30 | 31 | public ShiftType getDayIndex1ShiftType() { 32 | return dayIndex1ShiftType; 33 | } 34 | 35 | public void setDayIndex1ShiftType(ShiftType dayIndex1ShiftType) { 36 | this.dayIndex1ShiftType = dayIndex1ShiftType; 37 | } 38 | 39 | public ShiftType getDayIndex2ShiftType() { 40 | return dayIndex2ShiftType; 41 | } 42 | 43 | public void setDayIndex2ShiftType(ShiftType dayIndex2ShiftType) { 44 | this.dayIndex2ShiftType = dayIndex2ShiftType; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "Work pattern: " + dayIndex0ShiftType + ", " + dayIndex1ShiftType + ", " + dayIndex2ShiftType; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/pattern/WeekendDefinition.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.pattern; 2 | 3 | import java.util.EnumSet; 4 | 5 | public enum WeekendDefinition { 6 | SATURDAY_SUNDAY("SaturdaySunday", 7 | DayOfWeek.SATURDAY, DayOfWeek.SUNDAY), 8 | FRIDAY_SATURDAY_SUNDAY("FridaySaturdaySunday", 9 | DayOfWeek.FRIDAY, DayOfWeek.SATURDAY, DayOfWeek.SUNDAY), 10 | FRIDAY_SATURDAY_SUNDAY_MONDAY("FridaySaturdaySundayMonday", 11 | DayOfWeek.FRIDAY, DayOfWeek.SATURDAY, DayOfWeek.SUNDAY, DayOfWeek.MONDAY), 12 | SATURDAY_SUNDAY_MONDAY("SaturdaySundayMonday", 13 | DayOfWeek.SATURDAY, DayOfWeek.SUNDAY, DayOfWeek.MONDAY), ; 14 | 15 | private EnumSet dayOfWeekSet; 16 | private DayOfWeek firstDayOfWeekend; 17 | private DayOfWeek lastDayOfWeekend; 18 | 19 | public static WeekendDefinition valueOfCode(String code) { 20 | for (WeekendDefinition weekendDefinition : values()) { 21 | if (code.equalsIgnoreCase(weekendDefinition.getCode())) { 22 | return weekendDefinition; 23 | } 24 | } 25 | return null; 26 | } 27 | 28 | private String code; 29 | 30 | private WeekendDefinition(String code, DayOfWeek dayOfWeekend1, DayOfWeek dayOfWeekend2) { 31 | this.code = code; 32 | this.dayOfWeekSet = EnumSet.of(dayOfWeekend1, dayOfWeekend2); 33 | this.firstDayOfWeekend = dayOfWeekend1; 34 | this.lastDayOfWeekend = dayOfWeekend2; 35 | } 36 | 37 | private WeekendDefinition(String code, DayOfWeek dayOfWeekend1, DayOfWeek dayOfWeekend2, DayOfWeek dayOfWeekend3) { 38 | this.code = code; 39 | this.dayOfWeekSet = EnumSet.of(dayOfWeekend1, dayOfWeekend2, dayOfWeekend3); 40 | this.firstDayOfWeekend = dayOfWeekend1; 41 | this.lastDayOfWeekend = dayOfWeekend3; 42 | } 43 | 44 | private WeekendDefinition(String code, DayOfWeek dayOfWeekend1, DayOfWeek dayOfWeekend2, DayOfWeek dayOfWeekend3, 45 | DayOfWeek dayOfWeekend4) { 46 | this.code = code; 47 | this.dayOfWeekSet = EnumSet.of(dayOfWeekend1, dayOfWeekend2, dayOfWeekend3, dayOfWeekend4); 48 | this.firstDayOfWeekend = dayOfWeekend1; 49 | this.lastDayOfWeekend = dayOfWeekend4; 50 | } 51 | 52 | public String getCode() { 53 | return code; 54 | } 55 | 56 | public DayOfWeek getFirstDayOfWeekend() { 57 | return firstDayOfWeekend; 58 | } 59 | 60 | public DayOfWeek getLastDayOfWeekend() { 61 | return lastDayOfWeekend; 62 | } 63 | 64 | public String toString() { 65 | return code; 66 | } 67 | 68 | public boolean isWeekend(DayOfWeek dayOfWeek) { 69 | return dayOfWeekSet.contains(dayOfWeek); 70 | } 71 | 72 | public int getWeekendLength() { 73 | return dayOfWeekSet.size(); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/pattern/WorkBeforeFreeSequencePattern.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.pattern; 2 | 3 | import javax.jdo.annotations.InheritanceStrategy; 4 | 5 | import com.thoughtworks.xstream.annotations.XStreamAlias; 6 | import com.rotabuilder.dom.domain.shift.ShiftType; 7 | 8 | @javax.jdo.annotations.PersistenceCapable 9 | @javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.SUPERCLASS_TABLE) 10 | 11 | @XStreamAlias("WorkBeforeFreeSequencePattern") 12 | public class WorkBeforeFreeSequencePattern extends Pattern { 13 | 14 | @javax.jdo.annotations.Column(allowsNull = "true") 15 | private DayOfWeek workDayOfWeek; // null means any 16 | 17 | @javax.jdo.annotations.Column(allowsNull = "true") 18 | private ShiftType workShiftType; // null means any 19 | 20 | @javax.jdo.annotations.Column(allowsNull = "false") 21 | private int freeDayLength; 22 | 23 | public DayOfWeek getWorkDayOfWeek() { 24 | return workDayOfWeek; 25 | } 26 | 27 | public void setWorkDayOfWeek(DayOfWeek workDayOfWeek) { 28 | this.workDayOfWeek = workDayOfWeek; 29 | } 30 | 31 | public ShiftType getWorkShiftType() { 32 | return workShiftType; 33 | } 34 | 35 | public void setWorkShiftType(ShiftType workShiftType) { 36 | this.workShiftType = workShiftType; 37 | } 38 | 39 | public int getFreeDayLength() { 40 | return freeDayLength; 41 | } 42 | 43 | public void setFreeDayLength(int freeDayLength) { 44 | this.freeDayLength = freeDayLength; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "Work " + workShiftType + " on " + workDayOfWeek + " followed by " + freeDayLength + " free days"; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/shift/Shift.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.shift; 2 | 3 | import javax.jdo.annotations.IdentityType; 4 | 5 | import com.thoughtworks.xstream.annotations.XStreamAlias; 6 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 7 | 8 | @javax.jdo.annotations.PersistenceCapable( 9 | identityType= IdentityType.DATASTORE, 10 | schema = "simple" 11 | ) 12 | @XStreamAlias("Shift") 13 | public class Shift extends AbstractPersistable { 14 | 15 | @javax.jdo.annotations.Column(allowsNull = "false") 16 | private ShiftDate shiftDate; 17 | 18 | @javax.jdo.annotations.Column(allowsNull = "false") 19 | private ShiftType shiftType; 20 | 21 | @javax.jdo.annotations.Column(allowsNull = "false") 22 | private int requiredEmployeeSize; 23 | 24 | public ShiftDate getShiftDate() { 25 | return shiftDate; 26 | } 27 | 28 | public void setShiftDate(ShiftDate shiftDate) { 29 | this.shiftDate = shiftDate; 30 | } 31 | 32 | public ShiftType getShiftType() { 33 | return shiftType; 34 | } 35 | 36 | public void setShiftType(ShiftType shiftType) { 37 | this.shiftType = shiftType; 38 | } 39 | 40 | public int getRequiredEmployeeSize() { 41 | return requiredEmployeeSize; 42 | } 43 | 44 | public void setRequiredEmployeeSize(int requiredEmployeeSize) { 45 | this.requiredEmployeeSize = requiredEmployeeSize; 46 | } 47 | 48 | public String getLabel() { 49 | return shiftType.getLabel() + " of " + shiftDate.getLabel(); 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return shiftDate + "/" + shiftType; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/shift/Shift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bibryam/rotabuilder/74bf5f1f2ce2b714063eed1e3a6aa63be9c5808e/dom/src/main/java/com/rotabuilder/dom/domain/shift/Shift.png -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/shift/ShiftAssignment.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.shift; 2 | 3 | import javax.jdo.annotations.IdentityType; 4 | 5 | import com.rotabuilder.dom.domain.contract.Contract; 6 | import com.rotabuilder.dom.domain.employee.Employee; 7 | import com.rotabuilder.dom.domain.solver.MovableShiftAssignmentSelectionFilter; 8 | import com.rotabuilder.dom.domain.solver.ShiftAssignmentDifficultyComparator; 9 | import com.thoughtworks.xstream.annotations.XStreamAlias; 10 | import com.rotabuilder.dom.domain.pattern.DayOfWeek; 11 | import com.rotabuilder.dom.domain.pattern.WeekendDefinition; 12 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 13 | import org.optaplanner.core.api.domain.entity.PlanningEntity; 14 | import org.optaplanner.core.api.domain.variable.PlanningVariable; 15 | import com.rotabuilder.dom.domain.solver.EmployeeStrengthComparator; 16 | 17 | @javax.jdo.annotations.PersistenceCapable( 18 | identityType= IdentityType.DATASTORE, 19 | schema = "simple" 20 | ) 21 | @PlanningEntity(difficultyComparatorClass = ShiftAssignmentDifficultyComparator.class, 22 | movableEntitySelectionFilter = MovableShiftAssignmentSelectionFilter.class) 23 | @XStreamAlias("ShiftAssignment") 24 | public class ShiftAssignment extends AbstractPersistable { 25 | 26 | @javax.jdo.annotations.Column(allowsNull = "false") 27 | private Shift shift; 28 | 29 | @javax.jdo.annotations.Column(allowsNull = "true") 30 | private Employee employee; 31 | 32 | public Shift getShift() { 33 | return shift; 34 | } 35 | 36 | public void setShift(Shift shift) { 37 | this.shift = shift; 38 | } 39 | 40 | @PlanningVariable(valueRangeProviderRefs = {"employeeRange"}, strengthComparatorClass = EmployeeStrengthComparator.class) 41 | public Employee getEmployee() { 42 | return employee; 43 | } 44 | 45 | public void setEmployee(Employee employee) { 46 | this.employee = employee; 47 | } 48 | 49 | // ************************************************************************ 50 | // Complex methods 51 | // ************************************************************************ 52 | 53 | public ShiftDate getShiftDate() { 54 | return shift.getShiftDate(); 55 | } 56 | 57 | public ShiftType getShiftType() { 58 | return shift.getShiftType(); 59 | } 60 | 61 | public int getShiftDateDayIndex() { 62 | return shift.getShiftDate().getDayIndex(); 63 | } 64 | 65 | public DayOfWeek getShiftDateDayOfWeek() { 66 | return shift.getShiftDate().getDayOfWeek(); 67 | } 68 | 69 | public Contract getContract() { 70 | if (employee == null) { 71 | return null; 72 | } 73 | return employee.getContract(); 74 | } 75 | 76 | public boolean isWeekend() { 77 | if (employee == null) { 78 | return false; 79 | } 80 | WeekendDefinition weekendDefinition = employee.getContract().getWeekendDefinition(); 81 | DayOfWeek dayOfWeek = shift.getShiftDate().getDayOfWeek(); 82 | return weekendDefinition.isWeekend(dayOfWeek); 83 | } 84 | 85 | public int getWeekendSundayIndex() { 86 | return shift.getShiftDate().getWeekendSundayIndex(); 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | return shift.toString(); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/shift/ShiftRepository.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.shift; 2 | 3 | import java.util.List; 4 | 5 | import com.rotabuilder.dom.domain.employee.Employee; 6 | import com.rotabuilder.dom.domain.pattern.DayOfWeek; 7 | import org.apache.isis.applib.annotation.DomainService; 8 | import org.apache.isis.applib.annotation.NatureOfService; 9 | import org.apache.isis.applib.annotation.Programmatic; 10 | import org.apache.isis.applib.services.registry.ServiceRegistry2; 11 | import org.apache.isis.applib.services.repository.RepositoryService; 12 | 13 | @DomainService( 14 | nature = NatureOfService.DOMAIN, 15 | repositoryFor = Shift.class 16 | ) 17 | public class ShiftRepository { 18 | 19 | @javax.inject.Inject 20 | RepositoryService repositoryService; 21 | 22 | @javax.inject.Inject 23 | ServiceRegistry2 serviceRegistry; 24 | 25 | public List listShiftTypes() { 26 | return repositoryService.allInstances(ShiftType.class); 27 | } 28 | public List listShiftDates() { 29 | return repositoryService.allInstances(ShiftDate.class); 30 | } 31 | 32 | public List listShifts() { 33 | return repositoryService.allInstances(Shift.class); 34 | } 35 | 36 | public ShiftType createShiftType(String code, String description, String startTimeString, String endTimeString, int index, boolean isNight) { 37 | final ShiftType object = new ShiftType(); 38 | object.setCode(code); 39 | object.setDescription(description); 40 | object.setStartTimeString(startTimeString); 41 | object.setEndTimeString(endTimeString); 42 | object.setIndex(index); 43 | object.setNight(isNight); 44 | 45 | serviceRegistry.injectServicesInto(object); 46 | object.init(); 47 | repositoryService.persist(object); 48 | return object; 49 | } 50 | 51 | public ShiftDate createShiftDate(String dateString, int dayIndex, DayOfWeek dayOfWeek) { 52 | final ShiftDate object = new ShiftDate(); 53 | object.setDateString(dateString); 54 | object.setDayIndex(dayIndex); 55 | object.setDayOfWeek(dayOfWeek); 56 | 57 | serviceRegistry.injectServicesInto(object); 58 | object.init(); 59 | repositoryService.persist(object); 60 | return object; 61 | } 62 | 63 | public Shift createShift(ShiftType shiftType, ShiftDate shiftDate, int requiredEmployeeSize) { 64 | final Shift object = new Shift(); 65 | object.setShiftType(shiftType); 66 | object.setShiftDate(shiftDate); 67 | object.setRequiredEmployeeSize(requiredEmployeeSize); 68 | 69 | serviceRegistry.injectServicesInto(object); 70 | object.init(); 71 | repositoryService.persist(object); 72 | return object; 73 | } 74 | 75 | public ShiftAssignment createShiftAssignment(Shift shift, Employee employee) { 76 | final ShiftAssignment object = new ShiftAssignment(); 77 | object.setShift(shift); 78 | object.setEmployee(employee); 79 | 80 | serviceRegistry.injectServicesInto(object); 81 | object.init(); 82 | repositoryService.persist(object); 83 | return object; 84 | } 85 | 86 | public List listShiftAssignments() { 87 | return repositoryService.allInstances(ShiftAssignment.class); 88 | } 89 | 90 | @Programmatic 91 | public List autoComplete(final String description) { 92 | return repositoryService.allInstances(ShiftType.class); 93 | } 94 | 95 | @Programmatic 96 | public List autoCompleteShiftDate(final String description) { 97 | return repositoryService.allInstances(ShiftDate.class); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/shift/ShiftType.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.shift; 2 | 3 | import java.util.Set; 4 | import java.util.TreeSet; 5 | import javax.jdo.annotations.IdentityType; 6 | 7 | import com.rotabuilder.dom.domain.employee.Skill; 8 | import com.rotabuilder.dom.domain.solver.AbstractPersistable; 9 | import com.thoughtworks.xstream.annotations.XStreamAlias; 10 | import org.apache.isis.applib.annotation.Action; 11 | import org.apache.isis.applib.annotation.Collection; 12 | import org.apache.isis.applib.annotation.DomainObject; 13 | import org.apache.isis.applib.annotation.SemanticsOf; 14 | 15 | @javax.jdo.annotations.PersistenceCapable( 16 | identityType= IdentityType.DATASTORE, 17 | schema = "simple" 18 | ) 19 | @DomainObject( 20 | autoCompleteRepository = ShiftRepository.class, 21 | autoCompleteAction = "autoComplete") 22 | @XStreamAlias("ShiftType") 23 | public class ShiftType extends AbstractPersistable { 24 | 25 | @javax.jdo.annotations.Column(allowsNull = "false") 26 | private String code; 27 | 28 | @javax.jdo.annotations.Column(allowsNull = "false") 29 | private int index; 30 | 31 | @javax.jdo.annotations.Column(allowsNull = "false") 32 | private String startTimeString; 33 | 34 | @javax.jdo.annotations.Column(allowsNull = "false") 35 | private String endTimeString; 36 | 37 | @javax.jdo.annotations.Column(allowsNull = "false") 38 | private boolean night; 39 | 40 | @javax.jdo.annotations.Column(allowsNull = "false") 41 | private String description; 42 | 43 | @javax.jdo.annotations.Persistent(table = "ShiftTypeSkills") 44 | @javax.jdo.annotations.Join() 45 | private Set skills = new TreeSet<>(); 46 | 47 | public Set getSkills() { 48 | return skills; 49 | } 50 | @Collection() 51 | public void setSkills(Set skills) { 52 | this.skills = skills; 53 | } 54 | 55 | @Action 56 | public ShiftType addSkill(Skill skill) { 57 | getSkills().add(skill); 58 | return this; 59 | } 60 | 61 | @Action( 62 | semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE 63 | ) 64 | public ShiftType removeSkill(Skill skill) { 65 | getSkills().remove(skill); 66 | return this; 67 | } 68 | 69 | @Action( 70 | semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE 71 | ) 72 | public void complete() { 73 | System.out.println("sss"); 74 | } 75 | 76 | public String getCode() { 77 | return code; 78 | } 79 | 80 | public void setCode(String code) { 81 | this.code = code; 82 | } 83 | 84 | public int getIndex() { 85 | return index; 86 | } 87 | 88 | public void setIndex(int index) { 89 | this.index = index; 90 | } 91 | 92 | public String getStartTimeString() { 93 | return startTimeString; 94 | } 95 | 96 | public void setStartTimeString(String startTimeString) { 97 | this.startTimeString = startTimeString; 98 | } 99 | 100 | public String getEndTimeString() { 101 | return endTimeString; 102 | } 103 | 104 | public void setEndTimeString(String endTimeString) { 105 | this.endTimeString = endTimeString; 106 | } 107 | 108 | public boolean isNight() { 109 | return night; 110 | } 111 | 112 | public void setNight(boolean night) { 113 | this.night = night; 114 | } 115 | 116 | public String getDescription() { 117 | return description; 118 | } 119 | 120 | public void setDescription(String description) { 121 | this.description = description; 122 | } 123 | 124 | public String getLabel() { 125 | return code + " (" + description + ")"; 126 | } 127 | 128 | @Override 129 | public String toString() { 130 | return code; 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/shift/ShiftType.layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/shift/ShiftTypeSkillRequirement.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.shift; 2 | 3 | import com.rotabuilder.dom.domain.employee.Skill; 4 | import com.thoughtworks.xstream.annotations.XStreamAlias; 5 | 6 | @XStreamAlias("ShiftTypeSkillRequirement") 7 | public class ShiftTypeSkillRequirement { 8 | 9 | private ShiftType shiftType; 10 | 11 | private Skill skill; 12 | 13 | public ShiftType getShiftType() { 14 | return shiftType; 15 | } 16 | 17 | public void setShiftType(ShiftType shiftType) { 18 | this.shiftType = shiftType; 19 | } 20 | 21 | public Skill getSkill() { 22 | return skill; 23 | } 24 | 25 | public void setSkill(Skill skill) { 26 | this.skill = skill; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return shiftType + "-" + skill; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/solver/EmployeeRosterParametrization.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.solver; 2 | 3 | import com.thoughtworks.xstream.annotations.XStreamAlias; 4 | import com.rotabuilder.dom.domain.shift.ShiftDate; 5 | 6 | @XStreamAlias("EmployeeRosterParametrization") 7 | public class EmployeeRosterParametrization extends AbstractPersistable { 8 | 9 | private ShiftDate firstShiftDate; 10 | private ShiftDate lastShiftDate; 11 | 12 | private ShiftDate planningWindowStart; 13 | 14 | public ShiftDate getFirstShiftDate() { 15 | return firstShiftDate; 16 | } 17 | 18 | public void setFirstShiftDate(ShiftDate firstShiftDate) { 19 | this.firstShiftDate = firstShiftDate; 20 | } 21 | 22 | public ShiftDate getLastShiftDate() { 23 | return lastShiftDate; 24 | } 25 | 26 | public void setLastShiftDate(ShiftDate lastShiftDate) { 27 | this.lastShiftDate = lastShiftDate; 28 | } 29 | 30 | public int getFirstShiftDateDayIndex() { 31 | return firstShiftDate.getDayIndex(); 32 | } 33 | 34 | public int getLastShiftDateDayIndex() { 35 | return lastShiftDate.getDayIndex(); 36 | } 37 | 38 | public ShiftDate getPlanningWindowStart() { 39 | return planningWindowStart; 40 | } 41 | 42 | public void setPlanningWindowStart(ShiftDate planningWindowStart) { 43 | this.planningWindowStart = planningWindowStart; 44 | } 45 | 46 | // ************************************************************************ 47 | // Worker methods 48 | // ************************************************************************ 49 | 50 | public boolean isInPlanningWindow(ShiftDate shiftDate) { 51 | return planningWindowStart.getDayIndex() <= shiftDate.getDayIndex(); 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return firstShiftDate + " - " + lastShiftDate; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/solver/EmployeeStrengthComparator.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.solver; 2 | 3 | import java.io.Serializable; 4 | import java.util.Comparator; 5 | 6 | import com.rotabuilder.dom.domain.employee.Employee; 7 | import org.apache.commons.lang3.builder.CompareToBuilder; 8 | 9 | public class EmployeeStrengthComparator implements Comparator, Serializable { 10 | 11 | public int compare(Employee a, Employee b) { 12 | // TODO refactor to DifficultyWeightFactory and use getContract().getContractLineList() 13 | // to sum maximumValue and minimumValue etc 14 | return new CompareToBuilder() 15 | .append(b.getWeekendLength(), a.getWeekendLength()) // Descending 16 | // .append(a.getId(), b.getId()) 17 | .toComparison(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/solver/MovableShiftAssignmentSelectionFilter.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.solver; 2 | 3 | import org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionFilter; 4 | import org.optaplanner.core.impl.score.director.ScoreDirector; 5 | import com.rotabuilder.dom.domain.shift.ShiftAssignment; 6 | import com.rotabuilder.dom.domain.shift.ShiftDate; 7 | 8 | public class MovableShiftAssignmentSelectionFilter implements SelectionFilter { 9 | 10 | public boolean accept(ScoreDirector scoreDirector, ShiftAssignment shiftAssignment) { 11 | EmployeeRoster employeeRoster = (EmployeeRoster) scoreDirector.getWorkingSolution(); 12 | return accept(employeeRoster, shiftAssignment); 13 | } 14 | 15 | public boolean accept(EmployeeRoster employeeRoster, ShiftAssignment shiftAssignment) { 16 | ShiftDate shiftDate = shiftAssignment.getShift().getShiftDate(); 17 | return employeeRoster.getEmployeeRosterParametrization().isInPlanningWindow(shiftDate); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/solver/PersistableIdComparator.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.solver; 2 | 3 | import java.io.Serializable; 4 | import java.util.Comparator; 5 | 6 | public class PersistableIdComparator implements Comparator, Serializable { 7 | 8 | public int compare(AbstractPersistable a, AbstractPersistable b) { 9 | return -1; 10 | // return new CompareToBuilder().append(a.getId(), b.getId()).toComparison(); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/domain/solver/ShiftAssignmentDifficultyComparator.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.solver; 2 | 3 | import java.io.Serializable; 4 | import java.util.Comparator; 5 | 6 | import org.apache.commons.lang3.builder.CompareToBuilder; 7 | import com.rotabuilder.dom.domain.shift.Shift; 8 | import com.rotabuilder.dom.domain.shift.ShiftAssignment; 9 | 10 | public class ShiftAssignmentDifficultyComparator implements Comparator, Serializable { 11 | 12 | public int compare(ShiftAssignment a, ShiftAssignment b) { 13 | Shift aShift = a.getShift(); 14 | Shift bShift = b.getShift(); 15 | return new CompareToBuilder() 16 | .append(bShift.getShiftDate(), aShift.getShiftDate()) // Descending 17 | .append(bShift.getShiftType(), aShift.getShiftType()) // Descending 18 | // For construction heuristics, scheduling the shifts in sequence is better 19 | .append(aShift.getRequiredEmployeeSize(), bShift.getRequiredEmployeeSize()) 20 | .toComparison(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/drools/EmployeeAssignmentTotal.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.drools; 2 | 3 | import java.io.Serializable; 4 | 5 | import org.apache.commons.lang3.builder.CompareToBuilder; 6 | import org.apache.commons.lang3.builder.EqualsBuilder; 7 | import org.apache.commons.lang3.builder.HashCodeBuilder; 8 | import com.rotabuilder.dom.domain.employee.Employee; 9 | import com.rotabuilder.dom.domain.contract.Contract; 10 | 11 | public class EmployeeAssignmentTotal implements Comparable, Serializable { 12 | 13 | private Employee employee; 14 | private int total; 15 | 16 | public EmployeeAssignmentTotal(Employee employee, int total) { 17 | this.employee = employee; 18 | this.total = total; 19 | } 20 | 21 | public Employee getEmployee() { 22 | return employee; 23 | } 24 | 25 | public void setEmployee(Employee employee) { 26 | this.employee = employee; 27 | } 28 | 29 | public int getTotal() { 30 | return total; 31 | } 32 | 33 | public void setTotal(int total) { 34 | this.total = total; 35 | } 36 | 37 | public boolean equals(Object o) { 38 | if (this == o) { 39 | return true; 40 | } else if (o instanceof EmployeeAssignmentTotal) { 41 | EmployeeAssignmentTotal other = (EmployeeAssignmentTotal) o; 42 | return new EqualsBuilder() 43 | .append(employee, other.employee) 44 | .append(total, other.total) 45 | .isEquals(); 46 | } else { 47 | return false; 48 | } 49 | } 50 | 51 | public int hashCode() { 52 | return new HashCodeBuilder() 53 | .append(employee) 54 | .append(total) 55 | .toHashCode(); 56 | } 57 | 58 | public int compareTo(EmployeeAssignmentTotal other) { 59 | return new CompareToBuilder() 60 | .append(employee, other.employee) 61 | .append(total, other.total) 62 | .toComparison(); 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return employee + " = " + total; 68 | } 69 | 70 | public Contract getEmployeeContract() { 71 | return employee.getContract(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/drools/EmployeeConsecutiveAssignmentEnd.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.drools; 2 | 3 | import java.io.Serializable; 4 | 5 | import org.apache.commons.lang3.builder.CompareToBuilder; 6 | import org.apache.commons.lang3.builder.EqualsBuilder; 7 | import org.apache.commons.lang3.builder.HashCodeBuilder; 8 | import com.rotabuilder.dom.domain.pattern.DayOfWeek; 9 | import com.rotabuilder.dom.domain.employee.Employee; 10 | import com.rotabuilder.dom.domain.shift.ShiftDate; 11 | import com.rotabuilder.dom.domain.pattern.WeekendDefinition; 12 | import com.rotabuilder.dom.domain.contract.Contract; 13 | 14 | public class EmployeeConsecutiveAssignmentEnd implements Comparable, Serializable { 15 | 16 | private Employee employee; 17 | private ShiftDate shiftDate; 18 | 19 | public EmployeeConsecutiveAssignmentEnd(Employee employee, ShiftDate shiftDate) { 20 | this.employee = employee; 21 | this.shiftDate = shiftDate; 22 | } 23 | 24 | public Employee getEmployee() { 25 | return employee; 26 | } 27 | 28 | public void setEmployee(Employee employee) { 29 | this.employee = employee; 30 | } 31 | 32 | public ShiftDate getShiftDate() { 33 | return shiftDate; 34 | } 35 | 36 | public void setShiftDate(ShiftDate shiftDate) { 37 | this.shiftDate = shiftDate; 38 | } 39 | 40 | public boolean equals(Object o) { 41 | if (this == o) { 42 | return true; 43 | } else if (o instanceof EmployeeConsecutiveAssignmentEnd) { 44 | EmployeeConsecutiveAssignmentEnd other = (EmployeeConsecutiveAssignmentEnd) o; 45 | return new EqualsBuilder() 46 | .append(employee, other.employee) 47 | .append(shiftDate, other.shiftDate) 48 | .isEquals(); 49 | } else { 50 | return false; 51 | } 52 | } 53 | 54 | public int hashCode() { 55 | return new HashCodeBuilder() 56 | .append(employee) 57 | .append(shiftDate) 58 | .toHashCode(); 59 | } 60 | 61 | public int compareTo(EmployeeConsecutiveAssignmentEnd other) { 62 | return new CompareToBuilder() 63 | .append(employee, other.employee) 64 | .append(shiftDate, other.shiftDate) 65 | .toComparison(); 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | return employee + " ... - " + shiftDate; 71 | } 72 | 73 | public Contract getContract() { 74 | return employee.getContract(); 75 | } 76 | 77 | public int getShiftDateDayIndex() { 78 | return shiftDate.getDayIndex(); 79 | } 80 | 81 | public boolean isWeekendAndNotLastDayOfWeekend() { 82 | WeekendDefinition weekendDefinition = employee.getContract().getWeekendDefinition(); 83 | DayOfWeek dayOfWeek = shiftDate.getDayOfWeek(); 84 | return weekendDefinition.isWeekend(dayOfWeek) && weekendDefinition.getLastDayOfWeekend() != dayOfWeek; 85 | } 86 | 87 | public int getDistanceToLastDayOfWeekend() { 88 | WeekendDefinition weekendDefinition = employee.getContract().getWeekendDefinition(); 89 | DayOfWeek dayOfWeek = shiftDate.getDayOfWeek(); 90 | return dayOfWeek.getDistanceToNext(weekendDefinition.getLastDayOfWeekend()); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/drools/EmployeeConsecutiveAssignmentStart.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.drools; 2 | 3 | import java.io.Serializable; 4 | 5 | import org.apache.commons.lang3.builder.CompareToBuilder; 6 | import org.apache.commons.lang3.builder.EqualsBuilder; 7 | import org.apache.commons.lang3.builder.HashCodeBuilder; 8 | import com.rotabuilder.dom.domain.pattern.DayOfWeek; 9 | import com.rotabuilder.dom.domain.employee.Employee; 10 | import com.rotabuilder.dom.domain.shift.ShiftDate; 11 | import com.rotabuilder.dom.domain.pattern.WeekendDefinition; 12 | import com.rotabuilder.dom.domain.contract.Contract; 13 | 14 | public class EmployeeConsecutiveAssignmentStart implements Comparable, 15 | Serializable { 16 | 17 | private Employee employee; 18 | private ShiftDate shiftDate; 19 | 20 | public EmployeeConsecutiveAssignmentStart(Employee employee, ShiftDate shiftDate) { 21 | this.employee = employee; 22 | this.shiftDate = shiftDate; 23 | } 24 | 25 | public Employee getEmployee() { 26 | return employee; 27 | } 28 | 29 | public void setEmployee(Employee employee) { 30 | this.employee = employee; 31 | } 32 | 33 | public ShiftDate getShiftDate() { 34 | return shiftDate; 35 | } 36 | 37 | public void setShiftDate(ShiftDate shiftDate) { 38 | this.shiftDate = shiftDate; 39 | } 40 | 41 | public boolean equals(Object o) { 42 | if (this == o) { 43 | return true; 44 | } else if (o instanceof EmployeeConsecutiveAssignmentStart) { 45 | EmployeeConsecutiveAssignmentStart other = (EmployeeConsecutiveAssignmentStart) o; 46 | return new EqualsBuilder() 47 | .append(employee, other.employee) 48 | .append(shiftDate, other.shiftDate) 49 | .isEquals(); 50 | } else { 51 | return false; 52 | } 53 | } 54 | 55 | public int hashCode() { 56 | return new HashCodeBuilder() 57 | .append(employee) 58 | .append(shiftDate) 59 | .toHashCode(); 60 | } 61 | 62 | public int compareTo(EmployeeConsecutiveAssignmentStart other) { 63 | return new CompareToBuilder() 64 | .append(employee, other.employee) 65 | .append(shiftDate, other.shiftDate) 66 | .toComparison(); 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return employee + " " + shiftDate + " - ..."; 72 | } 73 | 74 | public Contract getContract() { 75 | return employee.getContract(); 76 | } 77 | 78 | public int getShiftDateDayIndex() { 79 | return shiftDate.getDayIndex(); 80 | } 81 | 82 | public boolean isWeekendAndNotFirstDayOfWeekend() { 83 | WeekendDefinition weekendDefinition = employee.getContract().getWeekendDefinition(); 84 | DayOfWeek dayOfWeek = shiftDate.getDayOfWeek(); 85 | return weekendDefinition.isWeekend(dayOfWeek) && weekendDefinition.getFirstDayOfWeekend() != dayOfWeek; 86 | } 87 | 88 | public int getDistanceToFirstDayOfWeekend() { 89 | WeekendDefinition weekendDefinition = employee.getContract().getWeekendDefinition(); 90 | DayOfWeek dayOfWeek = shiftDate.getDayOfWeek(); 91 | return weekendDefinition.getFirstDayOfWeekend().getDistanceToNext(dayOfWeek); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/drools/EmployeeConsecutiveWeekendAssignmentEnd.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.drools; 2 | 3 | import java.io.Serializable; 4 | 5 | import org.apache.commons.lang3.builder.CompareToBuilder; 6 | import org.apache.commons.lang3.builder.EqualsBuilder; 7 | import org.apache.commons.lang3.builder.HashCodeBuilder; 8 | import com.rotabuilder.dom.domain.employee.Employee; 9 | import com.rotabuilder.dom.domain.contract.Contract; 10 | 11 | public class EmployeeConsecutiveWeekendAssignmentEnd implements Comparable, Serializable { 12 | 13 | private Employee employee; 14 | private int sundayIndex; 15 | 16 | public EmployeeConsecutiveWeekendAssignmentEnd(Employee employee, int sundayIndex) { 17 | this.employee = employee; 18 | this.sundayIndex = sundayIndex; 19 | } 20 | 21 | public Employee getEmployee() { 22 | return employee; 23 | } 24 | 25 | public void setEmployee(Employee employee) { 26 | this.employee = employee; 27 | } 28 | 29 | public int getSundayIndex() { 30 | return sundayIndex; 31 | } 32 | 33 | public void setSundayIndex(int sundayIndex) { 34 | this.sundayIndex = sundayIndex; 35 | } 36 | 37 | public boolean equals(Object o) { 38 | if (this == o) { 39 | return true; 40 | } else if (o instanceof EmployeeConsecutiveWeekendAssignmentEnd) { 41 | EmployeeConsecutiveWeekendAssignmentEnd other = (EmployeeConsecutiveWeekendAssignmentEnd) o; 42 | return new EqualsBuilder() 43 | .append(employee, other.employee) 44 | .append(sundayIndex, other.sundayIndex) 45 | .isEquals(); 46 | } else { 47 | return false; 48 | } 49 | } 50 | 51 | public int hashCode() { 52 | return new HashCodeBuilder() 53 | .append(employee) 54 | .append(sundayIndex) 55 | .toHashCode(); 56 | } 57 | 58 | public int compareTo(EmployeeConsecutiveWeekendAssignmentEnd other) { 59 | return new CompareToBuilder() 60 | .append(employee, other.employee) 61 | .append(sundayIndex, other.sundayIndex) 62 | .toComparison(); 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return employee + " weekend ... - " + sundayIndex; 68 | } 69 | 70 | public Contract getContract() { 71 | return employee.getContract(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/drools/EmployeeConsecutiveWeekendAssignmentStart.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.drools; 2 | 3 | import java.io.Serializable; 4 | 5 | import org.apache.commons.lang3.builder.CompareToBuilder; 6 | import org.apache.commons.lang3.builder.EqualsBuilder; 7 | import org.apache.commons.lang3.builder.HashCodeBuilder; 8 | import com.rotabuilder.dom.domain.employee.Employee; 9 | import com.rotabuilder.dom.domain.contract.Contract; 10 | 11 | public class EmployeeConsecutiveWeekendAssignmentStart implements Comparable, 12 | Serializable { 13 | 14 | private Employee employee; 15 | private int sundayIndex; 16 | 17 | public EmployeeConsecutiveWeekendAssignmentStart(Employee employee, int sundayIndex) { 18 | this.employee = employee; 19 | this.sundayIndex = sundayIndex; 20 | } 21 | 22 | public Employee getEmployee() { 23 | return employee; 24 | } 25 | 26 | public void setEmployee(Employee employee) { 27 | this.employee = employee; 28 | } 29 | 30 | public int getSundayIndex() { 31 | return sundayIndex; 32 | } 33 | 34 | public void setSundayIndex(int sundayIndex) { 35 | this.sundayIndex = sundayIndex; 36 | } 37 | 38 | public boolean equals(Object o) { 39 | if (this == o) { 40 | return true; 41 | } else if (o instanceof EmployeeConsecutiveWeekendAssignmentStart) { 42 | EmployeeConsecutiveWeekendAssignmentStart other = (EmployeeConsecutiveWeekendAssignmentStart) o; 43 | return new EqualsBuilder() 44 | .append(employee, other.employee) 45 | .append(sundayIndex, other.sundayIndex) 46 | .isEquals(); 47 | } else { 48 | return false; 49 | } 50 | } 51 | 52 | public int hashCode() { 53 | return new HashCodeBuilder() 54 | .append(employee) 55 | .append(sundayIndex) 56 | .toHashCode(); 57 | } 58 | 59 | public int compareTo(EmployeeConsecutiveWeekendAssignmentStart other) { 60 | return new CompareToBuilder() 61 | .append(employee, other.employee) 62 | .append(sundayIndex, other.sundayIndex) 63 | .toComparison(); 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return employee + " weekend " + sundayIndex + " - ..."; 69 | } 70 | 71 | public Contract getContract() { 72 | return employee.getContract(); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/drools/EmployeeFreeSequence.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.drools; 2 | 3 | import java.io.Serializable; 4 | 5 | import org.apache.commons.lang3.builder.CompareToBuilder; 6 | import org.apache.commons.lang3.builder.EqualsBuilder; 7 | import org.apache.commons.lang3.builder.HashCodeBuilder; 8 | import com.rotabuilder.dom.domain.employee.Employee; 9 | 10 | public class EmployeeFreeSequence implements Comparable, Serializable { 11 | 12 | private Employee employee; 13 | private int firstDayIndex; 14 | private int lastDayIndex; 15 | 16 | public EmployeeFreeSequence(Employee employee, int firstDayIndex, int lastDayIndex) { 17 | this.employee = employee; 18 | this.firstDayIndex = firstDayIndex; 19 | this.lastDayIndex = lastDayIndex; 20 | } 21 | 22 | public Employee getEmployee() { 23 | return employee; 24 | } 25 | 26 | public void setEmployee(Employee employee) { 27 | this.employee = employee; 28 | } 29 | 30 | public int getFirstDayIndex() { 31 | return firstDayIndex; 32 | } 33 | 34 | public void setFirstDayIndex(int firstDayIndex) { 35 | this.firstDayIndex = firstDayIndex; 36 | } 37 | 38 | public int getLastDayIndex() { 39 | return lastDayIndex; 40 | } 41 | 42 | public void setLastDayIndex(int lastDayIndex) { 43 | this.lastDayIndex = lastDayIndex; 44 | } 45 | 46 | public boolean equals(Object o) { 47 | if (this == o) { 48 | return true; 49 | } else if (o instanceof EmployeeFreeSequence) { 50 | EmployeeFreeSequence other = (EmployeeFreeSequence) o; 51 | return new EqualsBuilder() 52 | .append(employee, other.employee) 53 | .append(firstDayIndex, other.firstDayIndex) 54 | .append(lastDayIndex, other.lastDayIndex) 55 | .isEquals(); 56 | } else { 57 | return false; 58 | } 59 | } 60 | 61 | public int hashCode() { 62 | return new HashCodeBuilder() 63 | .append(employee) 64 | .append(firstDayIndex) 65 | .append(lastDayIndex) 66 | .toHashCode(); 67 | } 68 | 69 | public int compareTo(EmployeeFreeSequence other) { 70 | return new CompareToBuilder() 71 | .append(employee, other.employee) 72 | .append(firstDayIndex, other.firstDayIndex) 73 | .append(lastDayIndex, other.lastDayIndex) 74 | .toComparison(); 75 | } 76 | 77 | @Override 78 | public String toString() { 79 | return employee + " is free between " + firstDayIndex + " - " + lastDayIndex; 80 | } 81 | 82 | public int getDayLength() { 83 | return lastDayIndex - firstDayIndex + 1; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/drools/EmployeeWeekendSequence.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.drools; 2 | 3 | import java.io.Serializable; 4 | 5 | import org.apache.commons.lang3.builder.CompareToBuilder; 6 | import org.apache.commons.lang3.builder.EqualsBuilder; 7 | import org.apache.commons.lang3.builder.HashCodeBuilder; 8 | import com.rotabuilder.dom.domain.employee.Employee; 9 | 10 | public class EmployeeWeekendSequence implements Comparable, Serializable { 11 | 12 | private Employee employee; 13 | private int firstSundayIndex; 14 | private int lastSundayIndex; 15 | 16 | public EmployeeWeekendSequence(Employee employee, int firstSundayIndex, int lastSundayIndex) { 17 | this.employee = employee; 18 | this.firstSundayIndex = firstSundayIndex; 19 | this.lastSundayIndex = lastSundayIndex; 20 | } 21 | 22 | public Employee getEmployee() { 23 | return employee; 24 | } 25 | 26 | public void setEmployee(Employee employee) { 27 | this.employee = employee; 28 | } 29 | 30 | public int getFirstSundayIndex() { 31 | return firstSundayIndex; 32 | } 33 | 34 | public void setFirstSundayIndex(int firstSundayIndex) { 35 | this.firstSundayIndex = firstSundayIndex; 36 | } 37 | 38 | public int getLastSundayIndex() { 39 | return lastSundayIndex; 40 | } 41 | 42 | public void setLastSundayIndex(int lastSundayIndex) { 43 | this.lastSundayIndex = lastSundayIndex; 44 | } 45 | 46 | public boolean equals(Object o) { 47 | if (this == o) { 48 | return true; 49 | } else if (o instanceof EmployeeWeekendSequence) { 50 | EmployeeWeekendSequence other = (EmployeeWeekendSequence) o; 51 | return new EqualsBuilder() 52 | .append(employee, other.employee) 53 | .append(firstSundayIndex, other.firstSundayIndex) 54 | .append(lastSundayIndex, other.lastSundayIndex) 55 | .isEquals(); 56 | } else { 57 | return false; 58 | } 59 | } 60 | 61 | public int hashCode() { 62 | return new HashCodeBuilder() 63 | .append(employee) 64 | .append(firstSundayIndex) 65 | .append(lastSundayIndex) 66 | .toHashCode(); 67 | } 68 | 69 | public int compareTo(EmployeeWeekendSequence other) { 70 | return new CompareToBuilder() 71 | .append(employee, other.employee) 72 | .append(firstSundayIndex, other.firstSundayIndex) 73 | .append(lastSundayIndex, other.lastSundayIndex) 74 | .toComparison(); 75 | } 76 | 77 | @Override 78 | public String toString() { 79 | return employee + " is working the weekend of " + firstSundayIndex + " - " + lastSundayIndex; 80 | } 81 | 82 | public int getWeekendLength() { 83 | return ((lastSundayIndex - firstSundayIndex) / 7) + 1; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/drools/EmployeeWorkSequence.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.drools; 2 | 3 | import java.io.Serializable; 4 | 5 | import org.apache.commons.lang3.builder.CompareToBuilder; 6 | import org.apache.commons.lang3.builder.EqualsBuilder; 7 | import org.apache.commons.lang3.builder.HashCodeBuilder; 8 | import com.rotabuilder.dom.domain.employee.Employee; 9 | 10 | public class EmployeeWorkSequence implements Comparable, Serializable { 11 | 12 | private Employee employee; 13 | private int firstDayIndex; 14 | private int lastDayIndex; 15 | 16 | public EmployeeWorkSequence(Employee employee, int firstDayIndex, int lastDayIndex) { 17 | this.employee = employee; 18 | this.firstDayIndex = firstDayIndex; 19 | this.lastDayIndex = lastDayIndex; 20 | } 21 | 22 | public Employee getEmployee() { 23 | return employee; 24 | } 25 | 26 | public void setEmployee(Employee employee) { 27 | this.employee = employee; 28 | } 29 | 30 | public int getFirstDayIndex() { 31 | return firstDayIndex; 32 | } 33 | 34 | public void setFirstDayIndex(int firstDayIndex) { 35 | this.firstDayIndex = firstDayIndex; 36 | } 37 | 38 | public int getLastDayIndex() { 39 | return lastDayIndex; 40 | } 41 | 42 | public void setLastDayIndex(int lastDayIndex) { 43 | this.lastDayIndex = lastDayIndex; 44 | } 45 | 46 | public boolean equals(Object o) { 47 | if (this == o) { 48 | return true; 49 | } else if (o instanceof EmployeeWorkSequence) { 50 | EmployeeWorkSequence other = (EmployeeWorkSequence) o; 51 | return new EqualsBuilder() 52 | .append(employee, other.employee) 53 | .append(firstDayIndex, other.firstDayIndex) 54 | .append(lastDayIndex, other.lastDayIndex) 55 | .isEquals(); 56 | } else { 57 | return false; 58 | } 59 | } 60 | 61 | public int hashCode() { 62 | return new HashCodeBuilder() 63 | .append(employee) 64 | .append(firstDayIndex) 65 | .append(lastDayIndex) 66 | .toHashCode(); 67 | } 68 | 69 | public int compareTo(EmployeeWorkSequence other) { 70 | return new CompareToBuilder() 71 | .append(employee, other.employee) 72 | .append(firstDayIndex, other.firstDayIndex) 73 | .append(lastDayIndex, other.lastDayIndex) 74 | .toComparison(); 75 | } 76 | 77 | @Override 78 | public String toString() { 79 | return employee + " is working between " + firstDayIndex + " - " + lastDayIndex; 80 | } 81 | 82 | public int getDayLength() { 83 | return lastDayIndex - firstDayIndex + 1; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/move/EmployeeChangeMove.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.move; 2 | 3 | import java.util.Collection; 4 | import java.util.Collections; 5 | 6 | import org.apache.commons.lang3.ObjectUtils; 7 | import org.apache.commons.lang3.builder.EqualsBuilder; 8 | import org.apache.commons.lang3.builder.HashCodeBuilder; 9 | import org.optaplanner.core.impl.heuristic.move.AbstractMove; 10 | import org.optaplanner.core.impl.heuristic.move.Move; 11 | import org.optaplanner.core.impl.score.director.ScoreDirector; 12 | import com.rotabuilder.dom.domain.employee.Employee; 13 | import com.rotabuilder.dom.domain.shift.ShiftAssignment; 14 | 15 | public class EmployeeChangeMove extends AbstractMove { 16 | 17 | private ShiftAssignment shiftAssignment; 18 | private Employee toEmployee; 19 | 20 | public EmployeeChangeMove(ShiftAssignment shiftAssignment, Employee toEmployee) { 21 | this.shiftAssignment = shiftAssignment; 22 | this.toEmployee = toEmployee; 23 | } 24 | 25 | public boolean isMoveDoable(ScoreDirector scoreDirector) { 26 | return !ObjectUtils.equals(shiftAssignment.getEmployee(), toEmployee); 27 | } 28 | 29 | public Move createUndoMove(ScoreDirector scoreDirector) { 30 | return new EmployeeChangeMove(shiftAssignment, shiftAssignment.getEmployee()); 31 | } 32 | 33 | @Override 34 | protected void doMoveOnGenuineVariables(ScoreDirector scoreDirector) { 35 | EmployeeRosteringMoveHelper.moveEmployee(scoreDirector, shiftAssignment, toEmployee); 36 | } 37 | 38 | public Collection getPlanningEntities() { 39 | return Collections.singletonList(shiftAssignment); 40 | } 41 | 42 | public Collection getPlanningValues() { 43 | return Collections.singletonList(toEmployee); 44 | } 45 | 46 | public boolean equals(Object o) { 47 | if (this == o) { 48 | return true; 49 | } else if (o instanceof EmployeeChangeMove) { 50 | EmployeeChangeMove other = (EmployeeChangeMove) o; 51 | return new EqualsBuilder() 52 | .append(shiftAssignment, other.shiftAssignment) 53 | .append(toEmployee, other.toEmployee) 54 | .isEquals(); 55 | } else { 56 | return false; 57 | } 58 | } 59 | 60 | public int hashCode() { 61 | return new HashCodeBuilder() 62 | .append(shiftAssignment) 63 | .append(toEmployee) 64 | .toHashCode(); 65 | } 66 | 67 | public String toString() { 68 | return shiftAssignment + " {" + shiftAssignment.getEmployee() + " -> " + toEmployee + "}"; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/move/EmployeeMultipleChangeMove.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.move; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import org.apache.commons.lang3.ObjectUtils; 9 | import org.apache.commons.lang3.builder.EqualsBuilder; 10 | import org.apache.commons.lang3.builder.HashCodeBuilder; 11 | import org.optaplanner.core.impl.heuristic.move.AbstractMove; 12 | import org.optaplanner.core.impl.heuristic.move.Move; 13 | import org.optaplanner.core.impl.score.director.ScoreDirector; 14 | import com.rotabuilder.dom.domain.employee.Employee; 15 | import com.rotabuilder.dom.domain.shift.ShiftAssignment; 16 | 17 | public class EmployeeMultipleChangeMove extends AbstractMove { 18 | 19 | private Employee fromEmployee; 20 | private List shiftAssignmentList; 21 | private Employee toEmployee; 22 | 23 | public EmployeeMultipleChangeMove(Employee fromEmployee, List shiftAssignmentList, Employee toEmployee) { 24 | this.fromEmployee = fromEmployee; 25 | this.shiftAssignmentList = shiftAssignmentList; 26 | this.toEmployee = toEmployee; 27 | } 28 | 29 | public boolean isMoveDoable(ScoreDirector scoreDirector) { 30 | return !ObjectUtils.equals(fromEmployee, toEmployee); 31 | } 32 | 33 | public Move createUndoMove(ScoreDirector scoreDirector) { 34 | return new EmployeeMultipleChangeMove(toEmployee, shiftAssignmentList, fromEmployee); 35 | } 36 | 37 | @Override 38 | protected void doMoveOnGenuineVariables(ScoreDirector scoreDirector) { 39 | for (ShiftAssignment shiftAssignment : shiftAssignmentList) { 40 | if (!shiftAssignment.getEmployee().equals(fromEmployee)) { 41 | throw new IllegalStateException("The shiftAssignment (" + shiftAssignment + ") should have the same employee (" 42 | + fromEmployee + ") as the fromEmployee (" + fromEmployee + ")."); 43 | } 44 | EmployeeRosteringMoveHelper.moveEmployee(scoreDirector, shiftAssignment, toEmployee); 45 | } 46 | } 47 | 48 | public Collection getPlanningEntities() { 49 | return Collections.singletonList(shiftAssignmentList); 50 | } 51 | 52 | public Collection getPlanningValues() { 53 | return Arrays.asList(fromEmployee, toEmployee); 54 | } 55 | 56 | public boolean equals(Object o) { 57 | if (this == o) { 58 | return true; 59 | } else if (o instanceof EmployeeMultipleChangeMove) { 60 | EmployeeMultipleChangeMove other = (EmployeeMultipleChangeMove) o; 61 | return new EqualsBuilder() 62 | .append(fromEmployee, other.fromEmployee) 63 | .append(shiftAssignmentList, other.shiftAssignmentList) 64 | .append(toEmployee, other.toEmployee) 65 | .isEquals(); 66 | } else { 67 | return false; 68 | } 69 | } 70 | 71 | public int hashCode() { 72 | return new HashCodeBuilder() 73 | .append(fromEmployee) 74 | .append(shiftAssignmentList) 75 | .append(toEmployee) 76 | .toHashCode(); 77 | } 78 | 79 | public String toString() { 80 | return shiftAssignmentList + " {? -> " + toEmployee + "}"; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/move/EmployeeRosteringMoveHelper.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.move; 2 | 3 | import org.optaplanner.core.impl.score.director.ScoreDirector; 4 | import com.rotabuilder.dom.domain.employee.Employee; 5 | import com.rotabuilder.dom.domain.shift.ShiftAssignment; 6 | 7 | public class EmployeeRosteringMoveHelper { 8 | 9 | public static void moveEmployee(ScoreDirector scoreDirector, ShiftAssignment shiftAssignment, Employee toEmployee) { 10 | scoreDirector.beforeVariableChanged(shiftAssignment, "employee"); 11 | shiftAssignment.setEmployee(toEmployee); 12 | scoreDirector.afterVariableChanged(shiftAssignment, "employee"); 13 | } 14 | 15 | private EmployeeRosteringMoveHelper() { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/move/ShiftAssignmentSwapMove.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.move; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | 6 | import org.apache.commons.lang3.ObjectUtils; 7 | import org.apache.commons.lang3.builder.EqualsBuilder; 8 | import org.apache.commons.lang3.builder.HashCodeBuilder; 9 | import org.optaplanner.core.impl.heuristic.move.AbstractMove; 10 | import org.optaplanner.core.impl.heuristic.move.Move; 11 | import org.optaplanner.core.impl.score.director.ScoreDirector; 12 | import com.rotabuilder.dom.domain.employee.Employee; 13 | import com.rotabuilder.dom.domain.shift.ShiftAssignment; 14 | 15 | public class ShiftAssignmentSwapMove extends AbstractMove { 16 | 17 | private ShiftAssignment leftShiftAssignment; 18 | private ShiftAssignment rightShiftAssignment; 19 | 20 | public ShiftAssignmentSwapMove(ShiftAssignment leftShiftAssignment, ShiftAssignment rightShiftAssignment) { 21 | this.leftShiftAssignment = leftShiftAssignment; 22 | this.rightShiftAssignment = rightShiftAssignment; 23 | } 24 | 25 | public boolean isMoveDoable(ScoreDirector scoreDirector) { 26 | return !ObjectUtils.equals(leftShiftAssignment.getEmployee(), rightShiftAssignment.getEmployee()); 27 | } 28 | 29 | public Move createUndoMove(ScoreDirector scoreDirector) { 30 | return new ShiftAssignmentSwapMove(rightShiftAssignment, leftShiftAssignment); 31 | } 32 | 33 | @Override 34 | protected void doMoveOnGenuineVariables(ScoreDirector scoreDirector) { 35 | Employee oldLeftEmployee = leftShiftAssignment.getEmployee(); 36 | Employee oldRightEmployee = rightShiftAssignment.getEmployee(); 37 | EmployeeRosteringMoveHelper.moveEmployee(scoreDirector, leftShiftAssignment, oldRightEmployee); 38 | EmployeeRosteringMoveHelper.moveEmployee(scoreDirector, rightShiftAssignment, oldLeftEmployee); 39 | } 40 | 41 | public Collection getPlanningEntities() { 42 | return Arrays.asList(leftShiftAssignment, rightShiftAssignment); 43 | } 44 | 45 | public Collection getPlanningValues() { 46 | return Arrays.asList(leftShiftAssignment.getEmployee(), rightShiftAssignment.getEmployee()); 47 | } 48 | 49 | public boolean equals(Object o) { 50 | if (this == o) { 51 | return true; 52 | } else if (o instanceof ShiftAssignmentSwapMove) { 53 | ShiftAssignmentSwapMove other = (ShiftAssignmentSwapMove) o; 54 | return new EqualsBuilder() 55 | .append(leftShiftAssignment, other.leftShiftAssignment) 56 | .append(rightShiftAssignment, other.rightShiftAssignment) 57 | .isEquals(); 58 | } else { 59 | return false; 60 | } 61 | } 62 | 63 | public int hashCode() { 64 | return new HashCodeBuilder() 65 | .append(leftShiftAssignment) 66 | .append(rightShiftAssignment) 67 | .toHashCode(); 68 | } 69 | 70 | public String toString() { 71 | return leftShiftAssignment + " {" + leftShiftAssignment.getEmployee() + "} <-> " 72 | + rightShiftAssignment + " {" + rightShiftAssignment.getEmployee() + "}"; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/move/factory/EmployeeChangeMoveFactory.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.move.factory; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.rotabuilder.dom.solver.move.EmployeeChangeMove; 7 | import org.optaplanner.core.impl.heuristic.move.Move; 8 | import org.optaplanner.core.impl.heuristic.selector.move.factory.MoveListFactory; 9 | import com.rotabuilder.dom.domain.employee.Employee; 10 | import com.rotabuilder.dom.domain.solver.EmployeeRoster; 11 | import com.rotabuilder.dom.domain.shift.ShiftAssignment; 12 | import com.rotabuilder.dom.domain.solver.MovableShiftAssignmentSelectionFilter; 13 | 14 | public class EmployeeChangeMoveFactory implements MoveListFactory { 15 | 16 | private MovableShiftAssignmentSelectionFilter filter = new MovableShiftAssignmentSelectionFilter(); 17 | 18 | public List createMoveList(EmployeeRoster employeeRoster) { 19 | List moveList = new ArrayList(); 20 | List employeeList = employeeRoster.getEmployeeList(); 21 | for (ShiftAssignment shiftAssignment : employeeRoster.getShiftAssignmentList()) { 22 | if (filter.accept(employeeRoster, shiftAssignment)) { 23 | for (Employee employee : employeeList) { 24 | moveList.add(new EmployeeChangeMove(shiftAssignment, employee)); 25 | } 26 | } 27 | } 28 | return moveList; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /dom/src/main/java/com/rotabuilder/dom/solver/move/factory/ShiftAssignmentSwapMoveFactory.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.solver.move.factory; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.ListIterator; 7 | 8 | import com.rotabuilder.dom.domain.solver.EmployeeRoster; 9 | import com.rotabuilder.dom.solver.move.ShiftAssignmentSwapMove; 10 | import org.optaplanner.core.impl.heuristic.move.Move; 11 | import org.optaplanner.core.impl.heuristic.selector.move.factory.MoveListFactory; 12 | import com.rotabuilder.dom.domain.shift.ShiftAssignment; 13 | import com.rotabuilder.dom.domain.solver.MovableShiftAssignmentSelectionFilter; 14 | 15 | public class ShiftAssignmentSwapMoveFactory implements MoveListFactory { 16 | 17 | private MovableShiftAssignmentSelectionFilter filter = new MovableShiftAssignmentSelectionFilter(); 18 | 19 | public List createMoveList(EmployeeRoster employeeRoster) { 20 | // Filter out every immovable ShiftAssignment 21 | List shiftAssignmentList = new ArrayList( 22 | employeeRoster.getShiftAssignmentList()); 23 | for (Iterator it = shiftAssignmentList.iterator(); it.hasNext(); ) { 24 | ShiftAssignment shiftAssignment = it.next(); 25 | if (!filter.accept(employeeRoster, shiftAssignment)) { 26 | it.remove(); 27 | } 28 | } 29 | List moveList = new ArrayList(); 30 | for (ListIterator leftIt = shiftAssignmentList.listIterator(); leftIt.hasNext();) { 31 | ShiftAssignment leftShiftAssignment = leftIt.next(); 32 | for (ListIterator rightIt = shiftAssignmentList.listIterator(leftIt.nextIndex()); rightIt.hasNext();) { 33 | ShiftAssignment rightShiftAssignment = rightIt.next(); 34 | moveList.add(new ShiftAssignmentSwapMove(leftShiftAssignment, rightShiftAssignment)); 35 | } 36 | } 37 | return moveList; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /dom/src/test/java/com/rotabuilder/dom/domain/employee/EmployeeRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.employee; 2 | 3 | import java.util.List; 4 | 5 | import com.google.common.collect.Lists; 6 | import org.apache.isis.applib.services.registry.ServiceRegistry2; 7 | import org.apache.isis.applib.services.repository.RepositoryService; 8 | import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2; 9 | import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode; 10 | import org.hamcrest.Description; 11 | import org.hamcrest.Matcher; 12 | import org.hamcrest.TypeSafeMatcher; 13 | import org.jmock.Expectations; 14 | import org.jmock.Sequence; 15 | import org.jmock.auto.Mock; 16 | import org.junit.Before; 17 | import org.junit.Ignore; 18 | import org.junit.Rule; 19 | import org.junit.Test; 20 | 21 | import static org.assertj.core.api.Assertions.assertThat; 22 | 23 | public class EmployeeRepositoryTest { 24 | 25 | @Rule 26 | public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES); 27 | 28 | @Mock 29 | ServiceRegistry2 mockServiceRegistry; 30 | 31 | @Mock 32 | RepositoryService mockRepositoryService; 33 | 34 | EmployeeRepository repository; 35 | 36 | @Before 37 | public void setUp() throws Exception { 38 | repository = new EmployeeRepository(); 39 | repository.repositoryService = mockRepositoryService; 40 | repository.serviceRegistry = mockServiceRegistry; 41 | } 42 | 43 | public static class Create extends EmployeeRepositoryTest { 44 | 45 | @Test 46 | @Ignore 47 | public void happyCase() throws Exception { 48 | 49 | final String someName = "Foobar"; 50 | final String code = "code"; 51 | 52 | // given 53 | final Sequence seq = context.sequence("create"); 54 | context.checking(new Expectations() { 55 | { 56 | oneOf(mockServiceRegistry).injectServicesInto(with(any(Employee.class))); 57 | inSequence(seq); 58 | 59 | oneOf(mockRepositoryService).persist(with(nameOf(someName))); 60 | inSequence(seq); 61 | } 62 | 63 | }); 64 | 65 | // when 66 | final Employee obj = repository.create(someName, code, null); 67 | 68 | // then 69 | assertThat(obj).isNotNull(); 70 | assertThat(obj.getName()).isEqualTo(someName); 71 | } 72 | 73 | private static Matcher nameOf(final String name) { 74 | return new TypeSafeMatcher() { 75 | @Override 76 | protected boolean matchesSafely(final Employee item) { 77 | return name.equals(item.getName()); 78 | } 79 | 80 | @Override 81 | public void describeTo(final Description description) { 82 | description.appendText("has name of '" + name + "'"); 83 | } 84 | }; 85 | } 86 | } 87 | 88 | public static class ListAll extends EmployeeRepositoryTest { 89 | 90 | @Test 91 | public void happyCase() throws Exception { 92 | 93 | // given 94 | final List all = Lists.newArrayList(); 95 | 96 | context.checking(new Expectations() { 97 | { 98 | oneOf(mockRepositoryService).allInstances(Employee.class); 99 | will(returnValue(all)); 100 | } 101 | }); 102 | 103 | // when 104 | final List list = repository.listAll(); 105 | 106 | // then 107 | assertThat(list).isEqualTo(all); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /dom/src/test/java/com/rotabuilder/dom/domain/employee/EmployeeTest.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.dom.domain.employee; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | 8 | public class EmployeeTest { 9 | 10 | Employee employee; 11 | 12 | @Before 13 | public void setUp() throws Exception { 14 | employee = new Employee(); 15 | employee.setName("test"); 16 | } 17 | 18 | public static class Name extends EmployeeTest { 19 | 20 | @Test 21 | public void happyCase() throws Exception { 22 | // given 23 | String name = "test"; 24 | assertThat(employee.getName()).isNotEmpty(); 25 | 26 | // when 27 | employee.setName(name); 28 | 29 | // then 30 | assertThat(employee.getName()).isEqualTo(name); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /fixture/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | com.rotabuilder 7 | rotabuilder 8 | 1.0-SNAPSHOT 9 | 10 | 11 | fixture 12 | RotaBuilder Fixture 13 | 14 | 15 | 16 | ${project.groupId} 17 | dom 18 | 19 | 20 | 21 | org.datanucleus 22 | datanucleus-enhancer 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/DomainAppFixtureModule.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture; 2 | 3 | public final class DomainAppFixtureModule { 4 | 5 | 6 | } 7 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/DomainAppFixtureScriptsSpecificationProvider.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture; 2 | 3 | import com.rotabuilder.fixture.scenarios.RecreateEmployees; 4 | import org.apache.isis.applib.annotation.DomainService; 5 | import org.apache.isis.applib.annotation.NatureOfService; 6 | import org.apache.isis.applib.fixturescripts.FixtureScripts; 7 | import org.apache.isis.applib.services.fixturespec.FixtureScriptsSpecification; 8 | import org.apache.isis.applib.services.fixturespec.FixtureScriptsSpecificationProvider; 9 | 10 | /** 11 | * Specifies where to find fixtures, and other settings. 12 | */ 13 | @DomainService(nature = NatureOfService.DOMAIN) 14 | public class DomainAppFixtureScriptsSpecificationProvider implements FixtureScriptsSpecificationProvider { 15 | @Override 16 | public FixtureScriptsSpecification getSpecification() { 17 | return FixtureScriptsSpecification 18 | .builder(DomainAppFixtureScriptsSpecificationProvider.class) 19 | .with(FixtureScripts.MultipleExecutionStrategy.EXECUTE) 20 | .withRunScriptDefault(RecreateEmployees.class) 21 | .withRunScriptDropDown(FixtureScriptsSpecification.DropDownPolicy.CHOICES) 22 | .withRecreate(RecreateEmployees.class) 23 | .build(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/ContractTearDown.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import org.apache.isis.applib.fixturescripts.FixtureScript; 4 | import org.apache.isis.applib.services.jdosupport.IsisJdoSupport; 5 | 6 | public class ContractTearDown extends FixtureScript { 7 | 8 | @Override 9 | protected void execute(ExecutionContext executionContext) { 10 | isisJdoSupport.executeUpdate("delete from \"simple\".\"ContractLine\""); 11 | isisJdoSupport.executeUpdate("delete from \"simple\".\"Contract\""); 12 | } 13 | 14 | @javax.inject.Inject 15 | private IsisJdoSupport isisJdoSupport; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/EmployeeCreate.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import java.util.Set; 4 | 5 | import com.rotabuilder.dom.domain.contract.Contract; 6 | import com.rotabuilder.dom.domain.employee.Employee; 7 | import com.rotabuilder.dom.domain.employee.EmployeeMenu; 8 | import com.rotabuilder.dom.domain.employee.Skill; 9 | import org.apache.isis.applib.fixturescripts.FixtureScript; 10 | 11 | public class EmployeeCreate extends FixtureScript { 12 | 13 | //region > name (input) 14 | private String name; 15 | private String code; 16 | private Contract contract; 17 | private Set skills; 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | 27 | public String getCode() { 28 | return code; 29 | } 30 | 31 | public void setCode(String code) { 32 | this.code = code; 33 | } 34 | 35 | public Contract getContract() { 36 | return contract; 37 | } 38 | 39 | public void setContract(Contract contract) { 40 | this.contract = contract; 41 | } 42 | 43 | public Set getSkills() { 44 | return skills; 45 | } 46 | 47 | public void setSkills(Set skills) { 48 | this.skills = skills; 49 | } 50 | 51 | //region > nurse (output) 52 | private Employee employee; 53 | 54 | /** 55 | * The created simple object (output). 56 | * @return 57 | */ 58 | public Employee getEmployee() { 59 | return employee; 60 | } 61 | //endregion 62 | 63 | @Override 64 | protected void execute(final ExecutionContext ec) { 65 | 66 | String name = checkParam("name", ec, String.class); 67 | String code = checkParam("code", ec, String.class); 68 | Contract contract = checkParam("contract", ec, Contract.class); 69 | Set skills = checkParam("skills", ec, Set.class); 70 | 71 | this.employee = wrap(employeeMenu).create(name, code, contract); 72 | this.employee.setSkills(skills); 73 | 74 | // also make available to UI 75 | ec.addResult(this, employee); 76 | } 77 | 78 | @javax.inject.Inject 79 | private EmployeeMenu employeeMenu; 80 | 81 | } 82 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/EmployeeTearDown.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import org.apache.isis.applib.fixturescripts.FixtureScript; 4 | import org.apache.isis.applib.services.jdosupport.IsisJdoSupport; 5 | 6 | public class EmployeeTearDown extends FixtureScript { 7 | 8 | @Override 9 | protected void execute(ExecutionContext executionContext) { 10 | isisJdoSupport.executeUpdate("delete from \"simple\".\"EmployeeSkills\""); 11 | isisJdoSupport.executeUpdate("delete from \"simple\".\"Employee\""); 12 | } 13 | 14 | @javax.inject.Inject 15 | private IsisJdoSupport isisJdoSupport; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/PatternTearDown.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import org.apache.isis.applib.fixturescripts.FixtureScript; 4 | import org.apache.isis.applib.services.jdosupport.IsisJdoSupport; 5 | 6 | public class PatternTearDown extends FixtureScript { 7 | 8 | @Override 9 | protected void execute(ExecutionContext executionContext) { 10 | isisJdoSupport.executeUpdate("delete from \"simple\".\"Pattern\""); 11 | } 12 | 13 | 14 | @javax.inject.Inject 15 | private IsisJdoSupport isisJdoSupport; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/RequestCreate.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import java.util.Set; 4 | 5 | import com.rotabuilder.dom.domain.employee.DayOffRequest; 6 | import com.rotabuilder.dom.domain.employee.DayOnRequest; 7 | import com.rotabuilder.dom.domain.employee.EmployeeRepository; 8 | import com.rotabuilder.dom.domain.employee.ShiftOffRequest; 9 | import com.rotabuilder.dom.domain.employee.ShiftOnRequest; 10 | import com.rotabuilder.fixture.scenarios.MyFixtureScript; 11 | 12 | public class RequestCreate extends MyFixtureScript { 13 | private Set dayOnRequests; 14 | private Set dayOffRequests; 15 | private Set shiftOnRequests; 16 | private Set shiftOffRequests; 17 | 18 | public Set getDayOnRequests() { 19 | return dayOnRequests; 20 | } 21 | 22 | public void setDayOnRequests(Set dayOnRequests) { 23 | this.dayOnRequests = dayOnRequests; 24 | } 25 | 26 | public Set getDayOffRequests() { 27 | return dayOffRequests; 28 | } 29 | 30 | public void setDayOffRequests(Set dayOffRequests) { 31 | this.dayOffRequests = dayOffRequests; 32 | } 33 | 34 | public Set getShiftOnRequests() { 35 | return shiftOnRequests; 36 | } 37 | 38 | public void setShiftOnRequests(Set shiftOnRequests) { 39 | this.shiftOnRequests = shiftOnRequests; 40 | } 41 | 42 | public Set getShiftOffRequests() { 43 | return shiftOffRequests; 44 | } 45 | 46 | public void setShiftOffRequests(Set shiftOffRequests) { 47 | this.shiftOffRequests = shiftOffRequests; 48 | } 49 | 50 | @Override 51 | protected void doExecute(final ExecutionContext ec) { 52 | Set dayOnRequests = checkParam("dayOnRequests", ec, Set.class); 53 | Set dayOffRequests = checkParam("dayOffRequests", ec, Set.class); 54 | Set shiftOnRequests = checkParam("shiftOnRequests", ec, Set.class); 55 | Set shiftOffRequests = checkParam("shiftOffRequests", ec, Set.class); 56 | 57 | for (DayOnRequest dayOnRequest : dayOnRequests) { 58 | final DayOnRequest persisted = wrap(employeeRepository).createDayOnRequest(dayOnRequest.getEmployee(), dayOnRequest.getShiftDate(), dayOnRequest.getWeight()); 59 | ec.addResult(this, persisted); 60 | } 61 | 62 | for (DayOffRequest dayOffRequest : dayOffRequests) { 63 | final DayOffRequest persisted = wrap(employeeRepository).createDayOffRequest(dayOffRequest.getEmployee(), dayOffRequest.getShiftDate(), dayOffRequest.getWeight()); 64 | ec.addResult(this, persisted); 65 | } 66 | 67 | for (ShiftOnRequest shiftOnRequest : shiftOnRequests) { 68 | final ShiftOnRequest persisted = wrap(employeeRepository).createShiftOnRequest(shiftOnRequest.getEmployee(), shiftOnRequest.getShift(), shiftOnRequest.getWeight()); 69 | ec.addResult(this, persisted); 70 | } 71 | 72 | for (ShiftOffRequest shiftOffRequest : shiftOffRequests) { 73 | final ShiftOffRequest persisted = wrap(employeeRepository).createShiftOffRequest(shiftOffRequest.getEmployee(), shiftOffRequest.getShift(), shiftOffRequest.getWeight()); 74 | ec.addResult(this, persisted); 75 | } 76 | } 77 | 78 | @javax.inject.Inject 79 | private EmployeeRepository employeeRepository; 80 | } 81 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/RequestlTearDown.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import org.apache.isis.applib.fixturescripts.FixtureScript; 4 | import org.apache.isis.applib.services.jdosupport.IsisJdoSupport; 5 | 6 | public class RequestlTearDown extends FixtureScript { 7 | 8 | @Override 9 | protected void execute(ExecutionContext executionContext) { 10 | isisJdoSupport.executeUpdate("delete from \"simple\".\"DayOnRequest\""); 11 | isisJdoSupport.executeUpdate("delete from \"simple\".\"DayOffRequest\""); 12 | isisJdoSupport.executeUpdate("delete from \"simple\".\"ShiftOnRequest\""); 13 | isisJdoSupport.executeUpdate("delete from \"simple\".\"ShiftOffRequest\""); 14 | } 15 | 16 | @javax.inject.Inject 17 | private IsisJdoSupport isisJdoSupport; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/ShiftCreate.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import com.rotabuilder.dom.domain.shift.Shift; 4 | import com.rotabuilder.dom.domain.shift.ShiftDate; 5 | import com.rotabuilder.dom.domain.shift.ShiftRepository; 6 | import com.rotabuilder.dom.domain.shift.ShiftType; 7 | import org.apache.isis.applib.fixturescripts.FixtureScript; 8 | 9 | public class ShiftCreate extends FixtureScript { 10 | 11 | private ShiftType shiftType; 12 | private ShiftDate shiftDate; 13 | private Integer requiredEmployeeSize; 14 | private Shift shift; 15 | 16 | public ShiftType getShiftType() { 17 | return shiftType; 18 | } 19 | 20 | public void setShiftType(ShiftType shiftType) { 21 | this.shiftType = shiftType; 22 | } 23 | 24 | public ShiftDate getShiftDate() { 25 | return shiftDate; 26 | } 27 | 28 | public void setShiftDate(ShiftDate shiftDate) { 29 | this.shiftDate = shiftDate; 30 | } 31 | 32 | public Integer getRequiredEmployeeSize() { 33 | return requiredEmployeeSize; 34 | } 35 | 36 | public void setRequiredEmployeeSize(Integer requiredEmployeeSize) { 37 | this.requiredEmployeeSize = requiredEmployeeSize; 38 | } 39 | 40 | public Shift getShift() { 41 | return shift; 42 | } 43 | 44 | public void setShift(Shift shift) { 45 | this.shift = shift; 46 | } 47 | 48 | @Override 49 | protected void execute(final ExecutionContext ec) { 50 | 51 | ShiftType shiftType = checkParam("shiftType", ec, ShiftType.class); 52 | ShiftDate shiftDate = checkParam("shiftDate", ec, ShiftDate.class); 53 | Integer requiredEmployeeSize = checkParam("requiredEmployeeSize", ec, Integer.class); 54 | 55 | this.shift = wrap(shiftRepository).createShift(shiftType, shiftDate, requiredEmployeeSize); 56 | 57 | // also make available to UI 58 | ec.addResult(this, shiftDate); 59 | } 60 | 61 | @javax.inject.Inject 62 | private ShiftRepository shiftRepository; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/ShiftDateCreate.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import com.rotabuilder.dom.domain.pattern.DayOfWeek; 4 | import com.rotabuilder.dom.domain.shift.ShiftDate; 5 | import com.rotabuilder.dom.domain.shift.ShiftRepository; 6 | import org.apache.isis.applib.fixturescripts.FixtureScript; 7 | 8 | public class ShiftDateCreate extends FixtureScript { 9 | 10 | private String dateString; 11 | private int dayIndex; 12 | private DayOfWeek dayOfWeek; 13 | 14 | public String getDateString() { 15 | return dateString; 16 | } 17 | 18 | public void setDateString(String dateString) { 19 | this.dateString = dateString; 20 | } 21 | 22 | public int getDayIndex() { 23 | return dayIndex; 24 | } 25 | 26 | public void setDayIndex(int dayIndex) { 27 | this.dayIndex = dayIndex; 28 | } 29 | 30 | public DayOfWeek getDayOfWeek() { 31 | return dayOfWeek; 32 | } 33 | 34 | public void setDayOfWeek(DayOfWeek dayOfWeek) { 35 | this.dayOfWeek = dayOfWeek; 36 | } 37 | 38 | public void setShiftDate(ShiftDate shiftDate) { 39 | this.shiftDate = shiftDate; 40 | } 41 | 42 | //region > nurse (output) 43 | private ShiftDate shiftDate; 44 | 45 | public ShiftDate getShiftDate() { 46 | return shiftDate; 47 | } 48 | 49 | @Override 50 | protected void execute(final ExecutionContext ec) { 51 | 52 | String dateString = checkParam("dateString", ec, String.class); 53 | Integer dayIndex = checkParam("dayIndex", ec, Integer.class); 54 | DayOfWeek dayOfWeek = checkParam("dayOfWeek", ec, DayOfWeek.class); 55 | 56 | this.shiftDate = wrap(shiftRepository).createShiftDate(dateString, dayIndex, dayOfWeek); 57 | 58 | // also make available to UI 59 | ec.addResult(this, shiftDate); 60 | } 61 | 62 | @javax.inject.Inject 63 | private ShiftRepository shiftRepository; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/ShiftDateTearDown.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import org.apache.isis.applib.fixturescripts.FixtureScript; 4 | import org.apache.isis.applib.services.jdosupport.IsisJdoSupport; 5 | 6 | public class ShiftDateTearDown extends FixtureScript { 7 | 8 | @Override 9 | protected void execute(ExecutionContext executionContext) { 10 | isisJdoSupport.executeUpdate("delete from \"simple\".\"ShiftDate\""); 11 | } 12 | 13 | 14 | @javax.inject.Inject 15 | private IsisJdoSupport isisJdoSupport; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/ShiftTearDown.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import org.apache.isis.applib.fixturescripts.FixtureScript; 4 | import org.apache.isis.applib.services.jdosupport.IsisJdoSupport; 5 | 6 | public class ShiftTearDown extends FixtureScript { 7 | 8 | @Override 9 | protected void execute(ExecutionContext executionContext) { 10 | isisJdoSupport.executeUpdate("delete from \"simple\".\"Shift\""); 11 | } 12 | 13 | 14 | @javax.inject.Inject 15 | private IsisJdoSupport isisJdoSupport; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/ShiftTypeCreate.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import java.util.Set; 4 | 5 | import com.rotabuilder.dom.domain.employee.Skill; 6 | import com.rotabuilder.dom.domain.shift.ShiftMenu; 7 | import com.rotabuilder.dom.domain.shift.ShiftType; 8 | import org.apache.isis.applib.fixturescripts.FixtureScript; 9 | 10 | public class ShiftTypeCreate extends FixtureScript { 11 | 12 | private String code; 13 | private String description; 14 | private String startTimeString; 15 | private String endTimeString; 16 | private int index; 17 | private boolean isNight; 18 | private Set skills; 19 | 20 | public String getCode() { 21 | return code; 22 | } 23 | 24 | public void setCode(String code) { 25 | this.code = code; 26 | } 27 | 28 | public int getIndex() { 29 | return index; 30 | } 31 | 32 | public void setIndex(int index) { 33 | this.index = index; 34 | } 35 | 36 | public String getStartTimeString() { 37 | return startTimeString; 38 | } 39 | 40 | public void setStartTimeString(String startTimeString) { 41 | this.startTimeString = startTimeString; 42 | } 43 | 44 | public String getEndTimeString() { 45 | return endTimeString; 46 | } 47 | 48 | public void setEndTimeString(String endTimeString) { 49 | this.endTimeString = endTimeString; 50 | } 51 | 52 | public boolean getIsNight() { 53 | return isNight; 54 | } 55 | 56 | public void setIsNight(boolean isNight) { 57 | this.isNight = isNight; 58 | } 59 | 60 | public String getDescription() { 61 | return description; 62 | } 63 | 64 | public void setDescription(String description) { 65 | this.description = description; 66 | } 67 | 68 | public void setShiftType(ShiftType shiftType) { 69 | this.shiftType = shiftType; 70 | } 71 | public void setSkills(Set skills) { 72 | this.skills = skills; 73 | } 74 | 75 | public Set getSkills() { 76 | return skills; 77 | } 78 | 79 | //region > nurse (output) 80 | private ShiftType shiftType; 81 | 82 | public ShiftType getShiftType() { 83 | return shiftType; 84 | } 85 | //endregion 86 | 87 | @Override 88 | protected void execute(final ExecutionContext ec) { 89 | String code = checkParam("code", ec, String.class); 90 | String description = checkParam("description", ec, String.class); 91 | String startTimeString = checkParam("startTimeString", ec, String.class); 92 | String endTimeString = checkParam("endTimeString", ec, String.class); 93 | int index = checkParam("index", ec, Integer.class); 94 | boolean isNight = checkParam("isNight", ec, Boolean.class); 95 | Set skills = checkParam("skills", ec, Set.class); 96 | 97 | this.shiftType = wrap(shiftMenu).createShiftType(code, description, startTimeString, endTimeString, index, isNight); 98 | this.shiftType.setSkills(skills); 99 | 100 | // also make available to UI 101 | ec.addResult(this, shiftType); 102 | } 103 | 104 | @javax.inject.Inject 105 | private ShiftMenu shiftMenu; 106 | 107 | } 108 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/ShiftTypeTearDown.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import org.apache.isis.applib.fixturescripts.FixtureScript; 4 | import org.apache.isis.applib.services.jdosupport.IsisJdoSupport; 5 | 6 | public class ShiftTypeTearDown extends FixtureScript { 7 | 8 | @Override 9 | protected void execute(ExecutionContext executionContext) { 10 | isisJdoSupport.executeUpdate("delete from \"simple\".\"ShiftTypeSkills\""); 11 | isisJdoSupport.executeUpdate("delete from \"simple\".\"ShiftType\""); 12 | } 13 | 14 | 15 | @javax.inject.Inject 16 | private IsisJdoSupport isisJdoSupport; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/SkillCreate.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import com.rotabuilder.dom.domain.employee.EmployeeMenu; 4 | import com.rotabuilder.dom.domain.employee.Skill; 5 | import com.rotabuilder.fixture.scenarios.MyFixtureScript; 6 | 7 | public class SkillCreate extends MyFixtureScript { 8 | 9 | //region > name (input) 10 | private String code; 11 | /** 12 | * Name of the object (required) 13 | */ 14 | public String getCode() { 15 | return code; 16 | } 17 | 18 | public SkillCreate setName(final String code) { 19 | this.code = code; 20 | return this; 21 | } 22 | //endregion 23 | 24 | 25 | //region > nurse (output) 26 | private Skill skill; 27 | 28 | /** 29 | * The created simple object (output). 30 | * @return 31 | */ 32 | public Skill getSkill() { 33 | return skill; 34 | } 35 | //endregion 36 | 37 | @Override 38 | protected void doExecute(final ExecutionContext ec) { 39 | 40 | String code = checkParam("code", ec, String.class); 41 | 42 | this.skill = wrap(employeeMenu).createSkill(code); 43 | 44 | // also make available to UI 45 | ec.addResult(this, skill); 46 | } 47 | 48 | @javax.inject.Inject 49 | private EmployeeMenu employeeMenu; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/dom/SkillTearDown.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.dom; 2 | 3 | import org.apache.isis.applib.fixturescripts.FixtureScript; 4 | import org.apache.isis.applib.services.jdosupport.IsisJdoSupport; 5 | 6 | public class SkillTearDown extends FixtureScript { 7 | 8 | @Override 9 | protected void execute(ExecutionContext executionContext) { 10 | isisJdoSupport.executeUpdate("delete from \"simple\".\"Skill\""); 11 | } 12 | 13 | 14 | @javax.inject.Inject 15 | private IsisJdoSupport isisJdoSupport; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/scenarios/MyFixtureScript.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.scenarios; 2 | 3 | import javax.inject.Inject; 4 | 5 | import org.apache.isis.applib.fixturescripts.FixtureScript; 6 | import org.apache.isis.applib.services.sudo.SudoService; 7 | 8 | public abstract class MyFixtureScript extends FixtureScript { 9 | 10 | @Override 11 | protected final void execute(final ExecutionContext ec) { 12 | 13 | sudoService.sudo("isis-module-security-admin", new Runnable() { 14 | @Override 15 | public void run() { 16 | doExecute(ec); 17 | } 18 | }); 19 | 20 | } 21 | 22 | protected abstract void doExecute(final ExecutionContext ec); 23 | 24 | @Inject 25 | SudoService sudoService; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/scenarios/RecreateShiftType.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.scenarios; 2 | 3 | import java.util.HashSet; 4 | import java.util.List; 5 | 6 | import com.google.common.collect.Lists; 7 | 8 | import com.rotabuilder.fixture.dom.ShiftTypeTearDown; 9 | import org.apache.isis.applib.annotation.Programmatic; 10 | 11 | import com.rotabuilder.dom.domain.employee.EmployeeRepository; 12 | import com.rotabuilder.dom.domain.employee.Skill; 13 | import com.rotabuilder.dom.domain.shift.ShiftType; 14 | import com.rotabuilder.fixture.dom.ShiftTypeCreate; 15 | 16 | public class RecreateShiftType extends MyFixtureScript { 17 | 18 | public RecreateShiftType() { 19 | withDiscoverability(Discoverability.DISCOVERABLE); 20 | } 21 | 22 | //region > number (optional input) 23 | private Integer number; 24 | 25 | /** 26 | * The number of objects to create, up to 10; optional, defaults to 3. 27 | */ 28 | public Integer getNumber() { 29 | return number; 30 | } 31 | 32 | public RecreateShiftType setNumber(final Integer number) { 33 | this.number = number; 34 | return this; 35 | } 36 | //endregion 37 | 38 | //region > skills (output) 39 | private final List shiftTypes = Lists.newArrayList(); 40 | 41 | /** 42 | * The skills created by this fixture (output). 43 | */ 44 | @Programmatic 45 | public List getShiftTypes() { 46 | return shiftTypes; 47 | } 48 | //endregion 49 | 50 | @Override 51 | protected void doExecute(final ExecutionContext ec) { 52 | 53 | ec.executeChild(this, new ShiftTypeTearDown()); 54 | 55 | final List skills = employeeRepository.listSkills(); 56 | 57 | ShiftTypeCreate shiftTypeCreateEarly = new ShiftTypeCreate(); 58 | shiftTypeCreateEarly.setCode("E"); 59 | shiftTypeCreateEarly.setDescription("Early"); 60 | shiftTypeCreateEarly.setStartTimeString("06:30:00"); 61 | shiftTypeCreateEarly.setEndTimeString("14:30:00"); 62 | shiftTypeCreateEarly.setIndex(0); 63 | shiftTypeCreateEarly.setIsNight("06:30:00".compareTo("14:30:00") > 0); 64 | shiftTypeCreateEarly.setSkills(new HashSet<>(skills)); 65 | 66 | ec.executeChild(this, shiftTypeCreateEarly.getCode(), shiftTypeCreateEarly); 67 | shiftTypes.add(shiftTypeCreateEarly.getShiftType()); 68 | 69 | ShiftTypeCreate shiftTypeCreateLate = new ShiftTypeCreate(); 70 | shiftTypeCreateLate.setCode("L"); 71 | shiftTypeCreateLate.setDescription("Late"); 72 | shiftTypeCreateLate.setStartTimeString("14:30:00"); 73 | shiftTypeCreateLate.setEndTimeString("22:30:00"); 74 | shiftTypeCreateLate.setIndex(1); 75 | shiftTypeCreateLate.setIsNight("14:30:00".compareTo("22:30:00") > 0); 76 | shiftTypeCreateLate.setSkills(new HashSet<>(skills)); 77 | 78 | ec.executeChild(this, shiftTypeCreateLate.getCode(), shiftTypeCreateLate); 79 | shiftTypes.add(shiftTypeCreateLate.getShiftType()); 80 | 81 | ShiftTypeCreate shiftTypeCreateNight = new ShiftTypeCreate(); 82 | shiftTypeCreateNight.setCode("N"); 83 | shiftTypeCreateNight.setDescription("Night"); 84 | shiftTypeCreateNight.setStartTimeString("22:30:00"); 85 | shiftTypeCreateNight.setEndTimeString("06:30:00"); 86 | shiftTypeCreateNight.setIndex(2); 87 | shiftTypeCreateNight.setIsNight("22:30:00".compareTo("06:30:00") > 0); 88 | shiftTypeCreateNight.setSkills(new HashSet<>(skills)); 89 | 90 | ec.executeChild(this, shiftTypeCreateNight.getCode(), shiftTypeCreateNight); 91 | shiftTypes.add(shiftTypeCreateNight.getShiftType()); 92 | } 93 | 94 | 95 | @javax.inject.Inject 96 | private EmployeeRepository employeeRepository; 97 | } 98 | -------------------------------------------------------------------------------- /fixture/src/main/java/com/rotabuilder/fixture/scenarios/RecreateSkills.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.fixture.scenarios; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import com.google.common.collect.Lists; 8 | 9 | import com.rotabuilder.fixture.dom.SkillCreate; 10 | import org.apache.isis.applib.annotation.Programmatic; 11 | 12 | import com.rotabuilder.dom.domain.employee.Skill; 13 | import com.rotabuilder.fixture.dom.SkillTearDown; 14 | 15 | public class RecreateSkills extends MyFixtureScript { 16 | 17 | public final List NAMES = Collections.unmodifiableList(Arrays.asList( 18 | "Nurse", "HeadNurse")); 19 | 20 | public RecreateSkills() { 21 | withDiscoverability(Discoverability.DISCOVERABLE); 22 | } 23 | 24 | //region > number (optional input) 25 | private Integer number; 26 | 27 | /** 28 | * The number of objects to create, up to 10; optional, defaults to 3. 29 | */ 30 | public Integer getNumber() { 31 | return number; 32 | } 33 | 34 | public RecreateSkills setNumber(final Integer number) { 35 | this.number = number; 36 | return this; 37 | } 38 | //endregion 39 | 40 | //region > skills (output) 41 | private final List skills = Lists.newArrayList(); 42 | 43 | /** 44 | * The skills created by this fixture (output). 45 | */ 46 | @Programmatic 47 | public List getSkills() { 48 | return skills; 49 | } 50 | //endregion 51 | 52 | @Override 53 | protected void doExecute(final ExecutionContext ec) { 54 | 55 | // defaults 56 | final int number = defaultParam("number", ec, 2); 57 | 58 | // validate 59 | if(number < 0 || number > NAMES.size()) { 60 | throw new IllegalArgumentException(String.format("number must be in range [0,%d)", NAMES.size())); 61 | } 62 | 63 | // 64 | // execute 65 | // 66 | ec.executeChild(RecreateSkills.this, new SkillTearDown()); 67 | 68 | for (int i = 0; i < number; i++) { 69 | final SkillCreate fs = new SkillCreate().setName(NAMES.get(i)); 70 | ec.executeChild(RecreateSkills.this, fs.getCode(), fs); 71 | skills.add(fs.getSkill()); 72 | } 73 | 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /integtests/src/test/java/com/rotabuilder/integtests/modules/DomainAppIntegTest.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.integtests.modules; 2 | 3 | import org.junit.BeforeClass; 4 | 5 | import org.apache.isis.core.integtestsupport.IntegrationTestAbstract; 6 | import org.apache.isis.core.integtestsupport.scenarios.ScenarioExecutionForIntegration; 7 | 8 | public abstract class DomainAppIntegTest extends IntegrationTestAbstract { 9 | 10 | @BeforeClass 11 | public static void initClass() { 12 | org.apache.log4j.PropertyConfigurator.configure("logging.properties"); 13 | DomainAppSystemInitializer.initIsft(); 14 | 15 | // instantiating will install onto ThreadLocal 16 | new ScenarioExecutionForIntegration(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /integtests/src/test/java/com/rotabuilder/integtests/modules/DomainAppSystemInitializer.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.integtests.modules; 2 | 3 | import java.util.Map; 4 | 5 | import com.google.common.collect.Maps; 6 | 7 | import org.apache.isis.core.integtestsupport.IsisSystemForTest; 8 | 9 | import com.rotabuilder.app.DomainAppAppManifest; 10 | 11 | public class DomainAppSystemInitializer { 12 | 13 | public static void initIsft() { 14 | IsisSystemForTest isft = IsisSystemForTest.getElseNull(); 15 | if(isft == null) { 16 | isft = new IsisSystemForTest.Builder() 17 | .withLoggingAt(org.apache.log4j.Level.INFO) 18 | .with(new DomainAppAppManifest() { 19 | @Override 20 | public Map getConfigurationProperties() { 21 | final Map map = Maps.newHashMap(); 22 | Util.withJavaxJdoRunInMemoryProperties(map); 23 | Util.withDataNucleusProperties(map); 24 | Util.withIsisIntegTestProperties(map); 25 | return map; 26 | } 27 | }) 28 | .build(); 29 | isft.setUpSystem(); 30 | IsisSystemForTest.set(isft); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /webapp/ide/eclipse/launch/.gitignore: -------------------------------------------------------------------------------- 1 | /SimpleApp-PROTOTYPE-jrebel.launch 2 | /SimpleApp-jrebel.launch 3 | -------------------------------------------------------------------------------- /webapp/ide/eclipse/launch/SimpleApp-PROTOTYPE-with-fixtures-bypass-security.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /webapp/ide/eclipse/launch/SimpleApp-PROTOTYPE-with-fixtures.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /webapp/ide/eclipse/launch/SimpleApp-PROTOTYPE.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /webapp/ide/eclipse/launch/SimpleApp-SERVER.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /webapp/ide/intellij/launch/README.txt: -------------------------------------------------------------------------------- 1 | Copy into workspace\.idea\runConfigurations directory, and adjust file paths for Maven tasks. 2 | 3 | -------------------------------------------------------------------------------- /webapp/ide/intellij/launch/SimpleApp_PROTOTYPE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 28 | -------------------------------------------------------------------------------- /webapp/ide/intellij/launch/SimpleApp_PROTOTYPE_with_fixtures-bypass-security.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 28 | -------------------------------------------------------------------------------- /webapp/ide/intellij/launch/SimpleApp_PROTOTYPE_with_fixtures.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 28 | -------------------------------------------------------------------------------- /webapp/ide/intellij/launch/SimpleApp_SERVER.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 28 | -------------------------------------------------------------------------------- /webapp/ide/intellij/launch/SimpleApp__enhance_only_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /webapp/lib/.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # explicitly ignoring Microsoft JDBC4 jar 3 | # (cannot redistribute, licensing) 4 | # 5 | sqljdbc4.jar 6 | -------------------------------------------------------------------------------- /webapp/src/main/java/com/rotabuilder/webapp/footer/CustomFooterPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package com.rotabuilder.webapp.footer; 20 | 21 | import org.apache.isis.viewer.wicket.model.common.PageParametersUtils; 22 | import org.apache.isis.viewer.wicket.ui.components.widgets.breadcrumbs.BreadcrumbPanel; 23 | import org.apache.isis.viewer.wicket.ui.components.widgets.themepicker.ThemeChooser; 24 | import org.apache.isis.viewer.wicket.ui.pages.about.AboutPage; 25 | import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract; 26 | import org.apache.wicket.MarkupContainer; 27 | import org.apache.wicket.markup.html.WebComponent; 28 | import org.apache.wicket.markup.html.basic.Label; 29 | import org.apache.wicket.markup.html.link.BookmarkablePageLink; 30 | import org.apache.wicket.model.Model; 31 | import org.apache.wicket.model.ResourceModel; 32 | import org.apache.wicket.request.mapper.parameter.PageParameters; 33 | 34 | /** 35 | * A panel for the default page footer 36 | */ 37 | public class CustomFooterPanel extends PanelAbstract> { 38 | 39 | private static final String ID_BREADCRUMBS = "breadcrumbs"; 40 | private static final String ID_ABOUT_LINK = "aboutLink"; 41 | private static final String ID_ABOUT_MESSAGE = "aboutMessage"; 42 | private static final String ID_THEME_PICKER = "themePicker"; 43 | 44 | /** 45 | * Constructor. 46 | * 47 | * @param id The component id 48 | */ 49 | public CustomFooterPanel(String id) { 50 | super(id); 51 | } 52 | 53 | @Override 54 | protected void onInitialize() { 55 | super.onInitialize(); 56 | 57 | addBreadcrumbs(); 58 | addAboutLink(); 59 | addThemePicker(); 60 | } 61 | 62 | private void addBreadcrumbs() { 63 | final BreadcrumbPanel breadcrumbPanel = new BreadcrumbPanel(ID_BREADCRUMBS); 64 | addOrReplace(breadcrumbPanel); 65 | } 66 | 67 | @Override 68 | protected void onConfigure() { 69 | super.onConfigure(); 70 | 71 | PageParameters parameters = getPage().getPageParameters(); 72 | setVisible(parameters.get(PageParametersUtils.ISIS_NO_FOOTER_PARAMETER_NAME).isNull()); 73 | } 74 | 75 | private void addAboutLink() { 76 | final BookmarkablePageLink aboutLink = new BookmarkablePageLink<>(ID_ABOUT_LINK, AboutPage.class); 77 | add(aboutLink); 78 | 79 | final Label aboutLabel = new Label(ID_ABOUT_MESSAGE, new ResourceModel("aboutLabel")); 80 | aboutLink.add(aboutLabel); 81 | addDevModeWarning(aboutLink); 82 | } 83 | 84 | /** 85 | * Adds a component that shows a warning sign next to "About" link in development mode 86 | * @param container The parent component 87 | */ 88 | private void addDevModeWarning(final MarkupContainer container) { 89 | final WebComponent devModeWarning = new WebComponent("devModeWarning"); 90 | devModeWarning.setVisible(getApplication().usesDevelopmentConfig()); 91 | container.add(devModeWarning); 92 | } 93 | 94 | private void addThemePicker() { 95 | final ThemeChooser themeChooser = new ThemeChooser(ID_THEME_PICKER); 96 | addOrReplace(themeChooser); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /webapp/src/main/java/com/rotabuilder/webapp/footer/CustomFooterPanelFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.rotabuilder.webapp.footer; 21 | 22 | import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract; 23 | import org.apache.isis.viewer.wicket.ui.ComponentType; 24 | import org.apache.wicket.Component; 25 | import org.apache.wicket.model.IModel; 26 | 27 | /** 28 | * {@link org.apache.isis.viewer.wicket.ui.ComponentFactory} to create container for the page footer. 29 | */ 30 | public class CustomFooterPanelFactory extends ComponentFactoryAbstract { 31 | 32 | private static final long serialVersionUID = 1L; 33 | 34 | public CustomFooterPanelFactory() { 35 | super(ComponentType.FOOTER, CustomFooterPanel.class); 36 | } 37 | 38 | @Override 39 | public ApplicationAdvice appliesTo(final IModel model) { 40 | return ApplicationAdvice.APPLIES; 41 | } 42 | 43 | @Override 44 | public Component createComponent(final String id, final IModel model) { 45 | return new CustomFooterPanel(id); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /webapp/src/main/java/com/rotabuilder/webapp/footer/MyComponentFactoryRegistrar.java: -------------------------------------------------------------------------------- 1 | package com.rotabuilder.webapp.footer; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistrar; 6 | import org.apache.isis.viewer.wicket.viewer.registries.components.ComponentFactoryRegistrarDefault; 7 | 8 | @Singleton 9 | public class MyComponentFactoryRegistrar extends ComponentFactoryRegistrarDefault { 10 | 11 | @Override 12 | public void addComponentFactories(ComponentFactoryRegistrar.ComponentFactoryList componentFactories) { 13 | super.addComponentFactories(componentFactories); 14 | componentFactories.replace(new CustomFooterPanelFactory()); 15 | } 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /webapp/src/main/jettyconsole/isis-banner.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bibryam/rotabuilder/74bf5f1f2ce2b714063eed1e3a6aa63be9c5808e/webapp/src/main/jettyconsole/isis-banner.pdn -------------------------------------------------------------------------------- /webapp/src/main/jettyconsole/isis-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bibryam/rotabuilder/74bf5f1f2ce2b714063eed1e3a6aa63be9c5808e/webapp/src/main/jettyconsole/isis-banner.png -------------------------------------------------------------------------------- /webapp/src/main/resources/com/rotabuilder/webapp/DomainApplication.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | 21 | # 22 | # This file is used by the Wicket viewer, acting as an app-level override for localized messages. 23 | # 24 | # Note that as of 1.11.0 it is possible to read localized messages from Isis' own translations.po file instead, 25 | # so there is much less reason to use this file. 26 | # 27 | 28 | 29 | -------------------------------------------------------------------------------- /webapp/src/main/resources/com/rotabuilder/webapp/footer/CustomFooterPanel.html: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 |
28 | 36 | 37 | 57 |
58 | 59 |
60 |
61 | 62 | 63 | -------------------------------------------------------------------------------- /webapp/src/main/resources/com/rotabuilder/webapp/welcome.html: -------------------------------------------------------------------------------- 1 | 2 | 20 |

21 | RotaBuilder™is a intelligent roster optimization application. 22 |
23 |

24 | -------------------------------------------------------------------------------- /webapp/src/main/resources/data/nurserostering/export/solution.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /webapp/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %d [%t] %-5p %m%n 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /webapp/src/main/resources/planner/EmployeeRosteringSolverConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | com.rotabuilder.dom.domain.solver.EmployeeRoster 5 | com.rotabuilder.dom.domain.shift.ShiftAssignment 6 | 7 | 8 | HARD_SOFT 9 | planner/EmployeeRosteringScoreRules.drl 10 | 11 | 12 | 13 | 17 | 10 18 | 19 | 20 | 21 | WEAKEST_FIT 22 | 23 | 24 | 25 | 26 | PHASE 27 | com.rotabuilder.dom.solver.move.factory.EmployeeChangeMoveFactory 28 | 29 | 30 | PHASE 31 | com.rotabuilder.dom.solver.move.factory.ShiftAssignmentSwapMoveFactory 32 | 33 | 34 | STEP 35 | com.rotabuilder.dom.solver.move.factory.ShiftAssignmentPillarPartSwapMoveFactory 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 7 48 | 49 | 50 | 800 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /webapp/src/main/resources/planner/planner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | domainapp.dom.nurse.ProblemDefinition 4 | domainapp.dom.nurse.Nurse 5 | 6 | 7 | HARD_SOFT 8 | domainapp.dom.nurse.ProblemScoreCalculator 9 | 10 | 11 | 12 | 3 13 | 14 | 15 | 16 | FIRST_FIT_DECREASING 17 | 18 | 19 | 20 | 21 | 7 22 | 23 | 24 | 1000 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /webapp/src/main/webapp/WEB-INF/authentication_shiro.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | 19 | 20 | # 21 | # if the shiro Subject is still authenticated, then just reuse. 22 | # Prior to 1.13.0, we forced an auto-logout, so set to 'true' to reinstate this behaviour. 23 | # See this thread for further info: http://markmail.org/message/hsjljwgkhhrzxbrm 24 | # 25 | #isis.authentication.shiro.autoLogoutIfAlreadyAuthenticated=false 26 | -------------------------------------------------------------------------------- /webapp/src/main/webapp/WEB-INF/persistor_datanucleus.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | # 19 | # configuration file for the JDO/DataNucleus objectstore 20 | # 21 | 22 | 23 | # 24 | # hook to perform additional initialization when JDO class metadata is loaded 25 | # default implementation will attempt to run 'create schema' for the specified schema. 26 | # 27 | # this implementation is installed by default: 28 | #isis.persistor.datanucleus.classMetadataLoadedListener=org.apache.isis.objectstore.jdo.datanucleus.CreateSchemaObjectFromClassMetadata 29 | 30 | 31 | # whether to persist the event data as a "clob" or as a "zipped" byte[] 32 | # default is "zipped" 33 | #isis.persistor.datanucleus.PublishingService.serializedForm=zipped 34 | 35 | 36 | ##################################################################### 37 | # 38 | # DataNucleus' configuration 39 | # 40 | # The 'isis.persistor.datanucleus.impl' prefix is stripped off, 41 | # remainder is passed through to DataNucleus 42 | # 43 | ##################################################################### 44 | 45 | isis.persistor.datanucleus.impl.datanucleus.schema.autoCreateAll=true 46 | isis.persistor.datanucleus.impl.datanucleus.schema.validateTables=true 47 | isis.persistor.datanucleus.impl.datanucleus.schema.validateConstraints=true 48 | 49 | 50 | # 51 | # Require explicit persistence (since entities are Comparable and using ObjectContracts#compareTo). 52 | # see http://www.datanucleus.org/products/accessplatform_3_0/jdo/transaction_types.html 53 | # 54 | isis.persistor.datanucleus.impl.datanucleus.persistenceByReachabilityAtCommit=false 55 | 56 | 57 | # 58 | # How column names are identified 59 | # (http://www.datanucleus.org/products/datanucleus/jdo/orm/datastore_identifiers.html) 60 | # 61 | isis.persistor.datanucleus.impl.datanucleus.identifier.case=MixedCase 62 | 63 | # 64 | # L2 cache 65 | # off except if explicitly marked as cacheable 66 | # http://www.datanucleus.org/products/datanucleus/jdo/cache.html 67 | # 68 | isis.persistor.datanucleus.impl.datanucleus.cache.level2.type=none 69 | isis.persistor.datanucleus.impl.datanucleus.cache.level2.mode=ENABLE_SELECTIVE 70 | 71 | 72 | 73 | # 74 | # uncomment to use JNDI rather than direct JDBC 75 | # 76 | #isis.persistor.datanucleus.impl.datanucleus.ConnectionFactoryName=java:comp/env/jdbc/quickstart 77 | 78 | # 79 | # uncomment to use JTA resource 80 | # 81 | #isis.persistor.datanucleus.impl.datanucleus.ConnectionFactory2Name=java:comp/env/jdbc/quickstart-nontx 82 | #isis.persistor.datanucleus.impl.javax.jdo.option.TransactionType=JTA 83 | 84 | 85 | 86 | # 87 | # 88 | # JDBC connection details 89 | # ... are in persistor.properties 90 | # 91 | # 92 | -------------------------------------------------------------------------------- /webapp/src/main/webapp/WEB-INF/shiro.ini: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | [main] 21 | 22 | contextFactory = org.apache.isis.security.shiro.IsisLdapContextFactory 23 | contextFactory.url = ldap://localhost:10389 24 | contextFactory.authenticationMechanism = CRAM-MD5 25 | contextFactory.systemAuthenticationMechanism = simple 26 | contextFactory.systemUsername = uid=admin,ou=system 27 | contextFactory.systemPassword = secret 28 | 29 | ldapRealm = org.apache.isis.security.shiro.IsisLdapRealm 30 | ldapRealm.contextFactory = $contextFactory 31 | 32 | ldapRealm.searchBase = ou=groups,o=mojo 33 | ldapRealm.groupObjectClass = groupOfUniqueNames 34 | ldapRealm.uniqueMemberAttribute = uniqueMember 35 | ldapRealm.uniqueMemberAttributeValueTemplate = uid={0} 36 | 37 | # optional mapping from physical groups to logical application roles 38 | #ldapRealm.rolesByGroup = \ 39 | # LDN_USERS: user_role,\ 40 | # NYK_USERS: user_role,\ 41 | # HKG_USERS: user_role,\ 42 | # GLOBAL_ADMIN: admin_role,\ 43 | # DEMOS: self-install_role 44 | 45 | ldapRealm.permissionsByRole=\ 46 | user_role = *:ToDoItemsJdo:*:*,\ 47 | *:ToDoItem:*:*; \ 48 | self-install_role = *:ToDoItemsFixturesService:install:* ; \ 49 | admin_role = * 50 | 51 | # to use ldap... 52 | # (see docs for details of how to setup users/groups in Apache Directory Studio). 53 | #securityManager.realms = $ldapRealm 54 | 55 | # to use .ini file 56 | #securityManager.realms = $iniRealm 57 | isisModuleSecurityRealm=org.isisaddons.module.security.shiro.IsisModuleSecurityRealm 58 | authenticationStrategy=org.isisaddons.module.security.shiro.AuthenticationStrategyForIsisModuleSecurityRealm 59 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy 60 | securityManager.realms = $isisModuleSecurityRealm 61 | 62 | 63 | 64 | # ----------------------------------------------------------------------------- 65 | # Users and their assigned roles 66 | # 67 | # Each line conforms to the format defined in the 68 | # org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc 69 | # ----------------------------------------------------------------------------- 70 | 71 | [users] 72 | # user = password, role1, role2, role3, ... 73 | 74 | 75 | admin = admin, admin_role 76 | user = user, user_role, self-install_role 77 | guest = guest, user_role 78 | 79 | 80 | 81 | # ----------------------------------------------------------------------------- 82 | # Roles with assigned permissions 83 | # 84 | # Each line conforms to the format defined in the 85 | # org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc 86 | # ----------------------------------------------------------------------------- 87 | 88 | [roles] 89 | # role = perm1, perm2, perm3, ... 90 | # perm in format: packageName:className:memberName:r,w 91 | 92 | user_role = *:Nurses:*:*,\ 93 | *:Nurse:*:* 94 | self-install_role = *:DomainAppFixtureService:*:* 95 | admin_role = * 96 | -------------------------------------------------------------------------------- /webapp/src/main/webapp/WEB-INF/viewer_restfulobjects.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | # 19 | # configuration file for the Restful Objects viewer 20 | # 21 | 22 | # the baseUrl for hrefs in the events generated by the RO EventSerializer 23 | isis.viewer.restfulobjects.RestfulObjectsSpecEventSerializer.baseUrl=http://localhost:8080/restful/ 24 | 25 | # renders param details in the (incorrect) form that they were for GSOC2013 viewers 26 | # isis.viewer.restfulobjects.gsoc2013.legacyParamDetails=true 27 | 28 | # whether to honor UI hints, in particular Render(EAGERLY). Defaults to false. 29 | #isis.viewer.restfulobjects.honorUiHints=false 30 | 31 | 32 | 33 | ############################################################################### 34 | # Non-standard configuration settings. 35 | # 36 | # If enabled of the following are enabled then the viewer is deviating from the 37 | # RO spec standard; compatibility may be compromised with RO clients. 38 | ############################################################################### 39 | 40 | # whether to show only object properties for object members 41 | # (on the object representation only) 42 | # Takes precedence over the other 'suppress' below. 43 | #isis.viewer.restfulobjects.objectPropertyValuesOnly=true 44 | 45 | # whether to suppress "describedby" links. Defaults to false. 46 | #isis.viewer.restfulobjects.suppressDescribedByLinks=true 47 | 48 | # whether to suppress "update" links. Defaults to false. 49 | #isis.viewer.restfulobjects.suppressUpdateLink=true 50 | 51 | # whether to suppress "id" json-prop for object members. Defaults to false. 52 | #isis.viewer.restfulobjects.suppressMemberId=true 53 | 54 | # whether to suppress "links" json-prop for object members 55 | # (on the object representation only). Defaults to false. 56 | #isis.viewer.restfulobjects.suppressMemberLinks=true 57 | 58 | # whether to suppress "extensions" json-prop for object members 59 | # (on the object representation only). Defaults to false. 60 | #isis.viewer.restfulobjects.suppressMemberExtensions=true 61 | 62 | # whether to suppress "disabledReason" json-prop for object members 63 | # (on the object representation only). Defaults to false. 64 | #isis.viewer.restfulobjects.suppressMemberDisabledReason=true 65 | 66 | ############################################################################### 67 | -------------------------------------------------------------------------------- /webapp/src/main/webapp/about/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bibryam/rotabuilder/74bf5f1f2ce2b714063eed1e3a6aa63be9c5808e/webapp/src/main/webapp/about/images/logo.jpg -------------------------------------------------------------------------------- /webapp/src/main/webapp/about/index.html: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | RotaBuilder™ 24 | 25 | 54 | 55 | 56 |
57 | RotaBuilder Logo 58 |

59 | The demo user/password is user/user and admin/admin for full access. 60 |

61 | 82 |

Created by @bibryam using Apache Isis and OptaPlanner. Fork this app on Github.

83 |
84 | 85 | 86 | -------------------------------------------------------------------------------- /webapp/src/main/webapp/css/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | -------------------------------------------------------------------------------- /webapp/src/main/webapp/images/spinning-icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bibryam/rotabuilder/74bf5f1f2ce2b714063eed1e3a6aa63be9c5808e/webapp/src/main/webapp/images/spinning-icon.gif -------------------------------------------------------------------------------- /webapp/src/main/webapp/scripts/application.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | /// here... 3 | }); --------------------------------------------------------------------------------