/** * Finds types extending {@link ServicesCoreBootstrapGuiceModule}: {@link * BeanImplementedServicesCoreGuiceModule}, {@link RESTImplementedServicesCoreGuiceModuleBase}, * etc if no type is found it returns null * * @param coreAppCode * @param coreModule * @return */ @SuppressWarnings("unchecked") private Set<Class<? extends ServicesCoreBootstrapGuiceModule>> _findCoreGuiceModulesOrNull( final Collection<CoreAppCode> coreAppCodes, final Class<? extends ServicesCoreBootstrapGuiceModule> coreGuiceModuleType) { List<String> pckgs = Lists.newLinkedList(); pckgs.add(ServicesCoreBootstrapGuiceModule.class.getPackage().getName()); pckgs.add(R01F.class.getPackage().getName()); // r01f.internal for (CoreAppCode coreAppCode : coreAppCodes) { pckgs.add(ServicesPackages.coreGuiceModulePackage(coreAppCode)); } Set<?> foundBootstrapModuleTypes = ServicesPackages.findSubTypesAt( coreGuiceModuleType, pckgs, this.getClass().getClassLoader()); // Filter the interfaces Set<Class<? extends ServicesCoreBootstrapGuiceModule>> outModuleTypes = (Set<Class<? extends ServicesCoreBootstrapGuiceModule>>) foundBootstrapModuleTypes; return FluentIterable.from(outModuleTypes) .filter( new Predicate<Class<? extends ServicesCoreBootstrapGuiceModule>>() { @Override public boolean apply(final Class<? extends ServicesCoreBootstrapGuiceModule> module) { return ReflectionUtils.isInstanciable(module); } }) .toSet(); }
/** * Returns the implementation type (REST, Bean, Mock, etc) of every services bootstrap module * listed at [appCode].client.properties.xml file to do so, it scans the packages under {core * appCode}.internal for types implementing {@link ServicesCoreBootstrapGuiceModule} * * <p>Some times a services implementation NEEDS (or DEPENDS UPON) another service implementation, * for example, the REST services implementation NEEDS the Bean services implementation because * REST services is only an ACCESS LAYER on top of the Bean services layer that is where the real * services logic resides. * * @return */ public Map<CoreAppAndModule, Collection<Class<? extends ServicesCoreBootstrapGuiceModule>>> findBootstrapGuiceModuleTypes() { if (_coreAppAndModules == null) return Maps.newHashMap(); // do not return a null config Map<CoreAppAndModule, Collection<Class<? extends ServicesCoreBootstrapGuiceModule>>> outModuleTypes = Maps.newHashMap(); // Iterate over all the app/module collection (each app/module can have many // ServicesCoreGuiceModules, ie: REST, Bean, etc.. one of them is the DEFAULT one) // NOTE: If more than one implementation is found, the BEAN has the highest priority followed by // the REST implementation // // for each app/module // 1.- Find the available ServicesCoreGuiceModules // 2.- For each found module found, try to find the needed modules // (sometimes a module (ie REST) NEEDS another modules (ie Bean or EJB) to do delegate the // work) // ... this task is a bit tricky since the order in which the modules are found is important // ... the checking of the presence of needed modules MUST be done AFTER all modules are // processed // Find guice modules implementing ServicesCoreGuiceModule either // BeanImplementedServicesGuiceModuleBase, RESTImplementedServicesGuiceModuleBase, // EJBImplementedServicesGuiceModuleBase, etc) Map<CoreAppAndModule, Collection<Class<? extends ServicesCoreBootstrapGuiceModule>>> coreBootstrapModuleTypesByApp = _findCoreBootstrapGuiceModuleTypesByAppModule(_coreAppAndModules); Collection<BootstrapModuleDependency> dependencies = Lists.newArrayList(); for (CoreAppAndModule coreAppModule : _coreAppAndModules) { CoreAppCode coreAppCode = coreAppModule.getAppCode(); CoreModule module = coreAppModule.getModule(); // [1] - Get the modules for the appCode Collection<Class<? extends ServicesCoreBootstrapGuiceModule>> appModuleCoreBootstrapModuleTypes = coreBootstrapModuleTypesByApp.get(coreAppModule); if (appModuleCoreBootstrapModuleTypes == null) { log.warn( "\t\t-{} core will NOT be bootstraped: There's NO type implementing {} at package {} or the {} package is NOT in the classpath. " + "If the {} core is to be bootstraped there MUST be AT LEAST a guice binding module extending {} at {} ", coreAppModule, ServicesCoreBootstrapGuiceModule.class, ServicesPackages.coreGuiceModulePackage(coreAppCode), ServicesPackages.coreGuiceModulePackage(coreAppCode), coreAppModule, ServicesCoreBootstrapGuiceModule.class, ServicesPackages.coreGuiceModulePackage(coreAppCode)); continue; } log.warn( "\t\t-{} core will be bootstraped with: {}", coreAppModule, coreBootstrapModuleTypesByApp.get(coreAppModule)); // [2] - for each found core bootstrap module try to find the needed modules (ie REST // bootstrap modules depends on BEAN bootstrap modules) for (Class<? extends ServicesCoreBootstrapGuiceModule> foundModuleType : appModuleCoreBootstrapModuleTypes) { if (ReflectionUtils.isInterface(foundModuleType)) continue; // Check if there's any module dependency set at @ServicesCore annotation ServicesCore servicesCoreAnnot = ReflectionUtils.typeAnnotation(foundModuleType, ServicesCore.class); // find the needed impl (the ServicesGuiceModule-implementing type MUST be annotated with // ServicesGuiceModuleDependencies) // (sometimes a service impl requires of another service impl, for example, REST services // USES Bean services) if (!CollectionUtils.of(servicesCoreAnnot.dependsOn()).contains(ServicesImpl.NULL)) { CoreAppAndModule ac = Strings.isNullOrEmpty(servicesCoreAnnot.fromOtherCoreAppCodeAndModule()) ? coreAppModule // by default dependencies are at the same coreAppCode/module : CoreAppAndModule.of(servicesCoreAnnot.fromOtherCoreAppCodeAndModule()); Collection<ServicesImpl> impls = Arrays.asList(servicesCoreAnnot.dependsOn()); BootstrapModuleDependency dependency = new BootstrapModuleDependency(coreAppModule, foundModuleType, ac, impls); dependencies.add(dependency); log.warn( "\t\t\t- Found {} CORE services bootstrap module (it has a dependency on other core component {}): {}", foundModuleType, dependency.debugInfo()); } else { log.warn( "\t\t\t- Found {} CORE services bootstrap module (no other bootstrap type dependency)", foundModuleType); } } // for bindingModules // [3] - put the core bootstrap modules in the output collection indexed by the // appCode/component outModuleTypes.put(coreAppModule, appModuleCoreBootstrapModuleTypes); } // for configuredBindingModules // Finally, make sure that the dependencies are satisfied if (CollectionUtils.hasData(dependencies)) { for (BootstrapModuleDependency dependency : dependencies) { Collection<Class<? extends ServicesCoreBootstrapGuiceModule>> otherCoreMods = outModuleTypes.get(dependency.getOtherAppAndComponent()); for (ServicesImpl depImpl : dependency.getDependencies()) { boolean isLoaded = false; if (CollectionUtils.hasData(otherCoreMods)) { for (Class<? extends ServicesCoreBootstrapGuiceModule> otherCoreMod : otherCoreMods) { if (ServicesImpl.fromBindingModule(otherCoreMod) == depImpl) { isLoaded = true; break; } } } if (!isLoaded) throw new IllegalStateException( Strings.customized( "{} (see @{})." + "BUT this module could NOT be loaded." + "Please ensure that a {} annotated type with impl={} attribute is accesible in the run-time classpath (maybe de dependent project is NOT deployed and available at the classpath)", dependency.debugInfo(), ServicesCore.class.getSimpleName(), ServicesCoreBootstrapGuiceModule.class, depImpl)); } } } // Return return outModuleTypes; }
/** * JVM arguments: -javaagent:D:/eclipse/local_libs/aspectj/lib/aspectjweaver.jar * -Daj.weaving.verbose=true * * <p>ClassPath: [aa88bConfig]/loc_tc [aa88fConfig]/loc_tc MYSQL_JDBC DRIVER */ @Slf4j @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class AA88LifeCycleServicesTest extends AA88TestBase { ///////////////////////////////////////////////////////////////////////////////////////// // FIELDS ///////////////////////////////////////////////////////////////////////////////////////// private final Collection<AA88GuaranteeOID> _testedGuaranteesOids = Lists.newArrayList(); ///////////////////////////////////////////////////////////////////////////////////////// // TEST ///////////////////////////////////////////////////////////////////////////////////////// // @Test public void testGuaranteeXml() { AA88ClientAPI api = TestAPIBase.getClientApi(AA88ClientAPI.class); AA88UserContext userContext = api.getUserContext(); String userContextXml = api.getModelObjectsMarshaller().xmlFromBean(userContext); System.out.println(userContextXml); AA88Guarantee mockGuarantee = AA88MockObjectsBuilder.buildMockGuarantee( TEST_FILELIST_FOLDER_PATH, AA88GuaranteedUnitID.forId("test1.txt")); String xml = api.getModelObjectsMarshaller().xmlFromBean(mockGuarantee); System.out.println(xml); } /** * Test the guarantee creation (startGuarantee), refresh (refreshGuarantee) and stop * (stopGuarantee) */ @Test public void testLifeCycle() { log.warn("============================================================="); log.warn("Test Life Cycle"); log.warn("============================================================="); AA88ClientAPI api = TestAPIBase.getClientApi(AA88ClientAPI.class); // Use a type that encapsulates all the tests AA88LifeCycleServicesTestHelper testHelp = new AA88LifeCycleServicesTestHelper(api, STORAGE_SERVICES); AA88Guarantee guarantee = testHelp.testLifeCycle( TEST_FILELIST_FOLDER_PATH, FileName.of("test2.txt"), Arrays.asList( AA88MethodToBeTested.START, AA88MethodToBeTested.REFRESH, AA88MethodToBeTested.STOP)); // store the tested guarantee oid just to remove it at the end _testedGuaranteesOids.add(guarantee.getOid()); } /** * Tests the refresh of all active guarantees, to do so, it first creates a bunch of gurantees * from the files at a dir */ // @Test public void testRefresh() { log.warn("============================================================="); log.warn("Test Refresh"); log.warn("============================================================="); AA88ClientAPI api = TestAPIBase.getClientApi(AA88ClientAPI.class); // Use a type that encapsulates all the tests final AA88LifeCycleServicesTestHelper testHelp = new AA88LifeCycleServicesTestHelper(api, STORAGE_SERVICES); // [1] - Create guarantees File testFileListsContainerFolder = new File(TEST_FILELIST_FOLDER_PATH.asAbsoluteString()); File[] testFileLists = testFileListsContainerFolder.listFiles(); Observable.from(testFileLists) .map( new Func1<File, AA88Guarantee>() { @Override public AA88Guarantee call(final File fileList) { log.warn("\n\n\n"); log.warn( "CREATE & DO A FIRST REFRESH for MOCK guarantee using fileList at {}", Paths.forPaths() .join(TEST_FILELIST_FOLDER_PATH, fileList.getName()) .asAbsoluteString()); AA88Guarantee guarantee = testHelp.testLifeCycle( TEST_FILELIST_FOLDER_PATH, FileName.of(fileList.getName()), Arrays.asList(AA88MethodToBeTested.START, AA88MethodToBeTested.REFRESH)); log.warn( "MOCK guarantee with oid={} CREATED & REFRESHED FOR THE FIRST TIME for fileList at {}", guarantee.getOid(), Paths.forPaths() .join(TEST_FILELIST_FOLDER_PATH, fileList.getName()) .asAbsoluteString()); log.warn("\n\n\n"); return guarantee; } }) .subscribe( new Observer<AA88Guarantee>() { @Override public void onNext(final AA88Guarantee guarantee) { _testedGuaranteesOids.add(guarantee.getOid()); } @Override public void onCompleted() { log.warn("\n\n\n\n\n\n"); log.warn( ":::::::: {} test guarantees with oids={} created__________________________", _testedGuaranteesOids.size(), _testedGuaranteesOids); } @Override public void onError(final Throwable th) { // BEWARE!!! RxJava will catch Exception and most Error. // Exceptions cannot be propagated out of RxJava // ... so even if Throwables.propagate(th) is used, the exception is NEVER thrown // outside RxJava // the only option is to use Exceptions.throwIfFatal(th) // (see https://github.com/ReactiveX/RxJava/issues/969) // Exceptions.throwIfFatal(th); th.printStackTrace(System.out); } }); // [2] - With the created guarantees, call refresh guarantee if (CollectionUtils.hasData(_testedGuaranteesOids)) { log.warn( ":::::::: With the created guarantees --> Refesh all Actives Guarantees _____________________________________________________________________"); // Call refresh all active guarantees and wait a moment to the scheduler to start api.guaranteesAPI() .getForLifeCycle() .refreshAllActiveGuarantees(AA88SourceSystemID.forId("PLATEA-Internet")); Threads.safeSleep(TimeLapse.createFor("5s")); // Check the process final Collection<BeingRefreshedGuarantee> refreshPendingGuarantees = FluentIterable.from(_testedGuaranteesOids) .transform( new Function<AA88GuaranteeOID, BeingRefreshedGuarantee>() { @Override public BeingRefreshedGuarantee apply(final AA88GuaranteeOID oid) { return new BeingRefreshedGuarantee(oid); } }) .toList(); long startTS = System.currentTimeMillis(); long elapsedMilis = 0; boolean anyRefreshPendingGuarantee = false; do { for (BeingRefreshedGuarantee b : refreshPendingGuarantees) { if (b.isRefreshed()) continue; // Check that there's NO minor version in requested status AA88Guarantee mockGuarantee = api.guaranteesAPI().getForCRUD().load(b.getOid()); if (mockGuarantee.existsMinorVersionInRequestedStatus()) { log.warn( "...the guarantee with oid={} unitId={} is still being refreshed (the notary is working)...give a moment to the notary to do it's work...", mockGuarantee.getOid(), mockGuarantee.getGuaranteedUnitId()); } else { log.warn( "The guarantee with oid={} unitId={} has been refreshed!... stop guaranteeing it", mockGuarantee.getOid(), mockGuarantee.getGuaranteedUnitId()); b.setRefreshed(true); } } anyRefreshPendingGuarantee = _anyRefreshPendingGuarantee(refreshPendingGuarantees); if (anyRefreshPendingGuarantee) { elapsedMilis = System.currentTimeMillis() - startTS; Threads.safeSleep(TimeLapse.createFor("5s")); } Assert.assertTrue( elapsedMilis < AA88LifeCycleServicesTestHelper.MAX_REFRESH_TIME_PER_GUARANTEE * _testedGuaranteesOids.size()); } while (anyRefreshPendingGuarantee); // Stop guaranteeing for (AA88GuaranteeOID oid : _testedGuaranteesOids) { log.warn("Stop guaranteein guarantee with oid={}", oid); api.guaranteesAPI().getForLifeCycle().stopGuaranteeingNow(oid); } // Check that all guarantees has been stoped for (AA88GuaranteeOID oid : _testedGuaranteesOids) { AA88Guarantee mockGuarantee = api.guaranteesAPI().getForCRUD().load(oid); Assert.assertTrue(!mockGuarantee.isActive()); } } else { log.warn("Could NOT create any mock guarantee!!!"); } } private static boolean _anyRefreshPendingGuarantee( final Collection<BeingRefreshedGuarantee> beingRefreshed) { return new Predicate<Collection<BeingRefreshedGuarantee>>() { private static final long serialVersionUID = 3675784786589279296L; @Override public boolean test(final Collection<BeingRefreshedGuarantee> c) { boolean anyPending = false; for (BeingRefreshedGuarantee b : c) { if (!b.isRefreshed()) { anyPending = true; break; } } return anyPending; } }.test(beingRefreshed); } ///////////////////////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////////////////////// @RequiredArgsConstructor @Accessors(prefix = "_") private class BeingRefreshedGuarantee { @Getter private final AA88GuaranteeOID _oid; @Getter @Setter private boolean _refreshed; } ///////////////////////////////////////////////////////////////////////////////////////// // RUN BEFORE AND AFTER EVERY TEST CASE, SO THEY CAN BE RUN MULTIPLE TIMES ///////////////////////////////////////////////////////////////////////////////////////// @Before public void setUp() throws Exception { // nothing } // @After public void tearDown() throws Exception { AA88ClientAPI api = TestAPIBase.getClientApi(AA88ClientAPI.class); if (CollectionUtils.hasData(_testedGuaranteesOids)) { for (AA88GuaranteeOID oid : _testedGuaranteesOids) { // [1]: Delete the guarantee publish requests at the DB (if exists) Collection<AA88GuaranteePublishRequestOID> deletedGuaranteePubRequestOids = api.guaranteesAPI() .getForPublishRequestCRUD() .deleteAllPublishRequestsForGuaranteeWithOid(oid); // [2]: Delete the guarantee record at the DB AA88Guarantee deletedGuarantee = api.guaranteesAPI().getForCRUD().delete(oid); // [3] - Delete the guarantee zip file & folder STORAGE_SERVICES.deleteGuaranteedUnitStorage( api.getUserContext(), deletedGuarantee.getSourceSystemId(), deletedGuarantee.getGuaranteedUnitId()); } } } }