/** * 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; }
/** * Finds types extending {@link ServicesCoreBootstrapGuiceModule}: {@link * BeanImplementedServicesCoreGuiceModule}, {@link RESTImplementedServicesCoreGuiceModuleBase}, * etc and returns them indexed by appCode / component * * @param coreAppCode * @param coreModule * @return */ private Map<CoreAppAndModule, Collection<Class<? extends ServicesCoreBootstrapGuiceModule>>> _findCoreBootstrapGuiceModuleTypesByAppModule( final Collection<CoreAppAndModule> coreAppAndComponents) { // get the core appcodes from the collection of core appCode/module Collection<CoreAppCode> coreAppCodes = FluentIterable.from(coreAppAndComponents) .transform( new Function<CoreAppAndModule, CoreAppCode>() { @Override public CoreAppCode apply(final CoreAppAndModule appAndComponent) { return appAndComponent.getAppCode(); } }) .toSet(); // Find the types implementing ServicesCoreGuiceModule at all the core appcodes (ie: r01t, // aa14b, aa81b, etc) Set<Class<? extends ServicesCoreBootstrapGuiceModule>> foundBootstrapModuleTypes = _findCoreGuiceModulesOrNull(coreAppCodes, ServicesCoreBootstrapGuiceModule.class); // Group the found core bootstrap module types by appCode/module Map<CoreAppAndModule, Collection<Class<? extends ServicesCoreBootstrapGuiceModule>>> outCoreModules = null; if (CollectionUtils.hasData(foundBootstrapModuleTypes)) { outCoreModules = Maps.newHashMapWithExpectedSize(coreAppCodes.size()); for (Class<? extends ServicesCoreBootstrapGuiceModule> bootstrapModuleType : foundBootstrapModuleTypes) { // get type appCode from the bootstrap module type's package (ie: r01t.internal.XXX) and // it's @ServiceCore annotation CoreAppCode appCode = ServicesPackages.appCodeFromCoreBootstrapModuleType( bootstrapModuleType); // use the service's core bootstrap type's package to get the // appCode CoreModule coreModule = ServicesPackages.appComponentFromCoreBootstrapModuleTypeOrThrow( bootstrapModuleType); // use the service's @ServicesCore annotation to get the // module CoreAppAndModule coreAppAndModule = CoreAppAndModule.of(appCode, coreModule); Collection<Class<? extends ServicesCoreBootstrapGuiceModule>> appModuleTypes = outCoreModules.get(coreAppAndModule); if (appModuleTypes == null) { appModuleTypes = Sets.newHashSet(); outCoreModules.put(coreAppAndModule, appModuleTypes); } appModuleTypes.add(bootstrapModuleType); } } else { log.warn( "There's NO type implementing {} in the classpath! For the CORE app codes {}, there MUST be AT LEAST a guice binding module extending {} at package {}", ServicesCoreBootstrapGuiceModule.class.getSimpleName(), coreAppCodes, ServicesCoreBootstrapGuiceModule.class, ServicesPackages.coreGuiceModulePackage(CoreAppCode.forId("[coreAppCode]")), ServicesCoreBootstrapGuiceModule.class); outCoreModules = Maps.newHashMap(); } return outCoreModules; }