/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.resource.accesscontrol.manager; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.TemporalType; import javax.persistence.TypedQuery; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.PersistenceHelper; import org.olat.core.gui.control.Event; import org.olat.core.id.Identity; import org.olat.core.id.Roles; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.FrameworkStartedEvent; import org.olat.core.util.event.FrameworkStartupEventChannel; import org.olat.core.util.event.GenericEventListener; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceImpl; import org.olat.resource.accesscontrol.AccessControlModule; import org.olat.resource.accesscontrol.Offer; import org.olat.resource.accesscontrol.OfferAccess; import org.olat.resource.accesscontrol.Price; import org.olat.resource.accesscontrol.method.AccessMethodHandler; import org.olat.resource.accesscontrol.model.AbstractAccessMethod; import org.olat.resource.accesscontrol.model.AccessMethod; import org.olat.resource.accesscontrol.model.AccessMethodSecurityCallback; import org.olat.resource.accesscontrol.model.FreeAccessMethod; import org.olat.resource.accesscontrol.model.OLATResourceAccess; import org.olat.resource.accesscontrol.model.OfferAccessImpl; import org.olat.resource.accesscontrol.model.TokenAccessMethod; import org.olat.resource.accesscontrol.provider.paypal.model.PaypalAccessMethod; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * * Description:<br> * This class manages the methods available to access the resource. * As standard "static" (static as singleton), there is Token and Free * based access. * * <P> * Initial Date: 18 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Service public class ACMethodDAO implements GenericEventListener { private static final OLog log = Tracing.createLoggerFor(ACMethodDAO.class); @Autowired private DB dbInstance; @Autowired private AccessControlModule acModule; @Autowired public ACMethodDAO(CoordinatorManager coordinatorManager) { coordinatorManager.getCoordinator().getEventBus().registerFor(this, null, FrameworkStartupEventChannel.getStartupEventChannel()); } @Override public void event(Event event) { if (event instanceof FrameworkStartedEvent && ((FrameworkStartedEvent) event).isEventOnThisNode()) { enableMethod(TokenAccessMethod.class, acModule.isTokenEnabled()); enableMethod(FreeAccessMethod.class, acModule.isFreeEnabled()); enableMethod(PaypalAccessMethod.class, acModule.isPaypalEnabled()); dbInstance.commitAndCloseSession(); } } public void enableMethod(Class<? extends AccessMethod> type, boolean enable) { StringBuilder sb = new StringBuilder(); sb.append("select method from ").append(type.getName()).append(" method"); List<AccessMethod> methods = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), AccessMethod.class) .getResultList(); if(methods.isEmpty() && enable) { try { AccessMethod method = type.newInstance(); Date now = new Date(); ((AbstractAccessMethod)method).setCreationDate(now); ((AbstractAccessMethod)method).setLastModified(now); dbInstance.saveObject(method); } catch (InstantiationException e) { log.error("Failed to instantiate an access method", e); } catch (IllegalAccessException e) { log.error("Failed to instantiate an access method", e); } } else { for(AccessMethod method:methods) { if(method.isEnabled() != enable) { ((AbstractAccessMethod)method).setEnabled(enable); ((AbstractAccessMethod)method).setLastModified(new Date()); dbInstance.updateObject(method); } } } } public boolean isValidMethodAvailable(OLATResource resource, Date atDate) { StringBuilder sb = new StringBuilder(); sb.append("select count(access.method) from acofferaccess access ") .append(" inner join access.offer offer") .append(" inner join offer.resource oResource") .append(" where access.valid=true") .append(" and offer.valid=true") .append(" and oResource.key=:resourceKey"); if(atDate != null) { sb.append(" and (offer.validFrom is null or offer.validFrom<=:atDate)") .append(" and (offer.validTo is null or offer.validTo>=:atDate)"); } TypedQuery<Number> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Number.class); query.setParameter("resourceKey", resource.getKey()); if(atDate != null) { query.setParameter("atDate", atDate, TemporalType.TIMESTAMP); } Number methods = query.getSingleResult(); return methods.intValue() > 0; } public List<AccessMethod> getAllMethods() { StringBuilder sb = new StringBuilder(); sb.append("select method from ").append(AbstractAccessMethod.class.getName()).append(" method"); return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), AccessMethod.class) .getResultList(); } public List<AccessMethod> getAvailableMethods(Identity identity, Roles roles) { StringBuilder sb = new StringBuilder(); sb.append("select method from ").append(AbstractAccessMethod.class.getName()).append(" method") .append(" where method.valid=true and method.enabled=true"); TypedQuery<AccessMethod> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), AccessMethod.class); if(identity != null) { //query.setLong("identityKey", identity.getKey()); } List<AccessMethod> methods = query.getResultList(); List<AccessMethod> allowedMethods = new ArrayList<AccessMethod>(); for(AccessMethod method:methods) { AccessMethodHandler handler = acModule.getAccessMethodHandler(method.getType()); AccessMethodSecurityCallback secCallback = handler.getSecurityCallback(identity, roles); if(secCallback.canUse()) { allowedMethods.add(method); } } return allowedMethods; } public List<AccessMethod> getAvailableMethodsByType(Class<? extends AccessMethod> type) { StringBuilder sb = new StringBuilder(); sb.append("select method from ").append(AbstractAccessMethod.class.getName()).append(" method") .append(" where method.valid=true") .append(" and method.class=").append(type.getName()); TypedQuery<AccessMethod> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), AccessMethod.class); List<AccessMethod> methods = query.getResultList(); return methods; } public List<OfferAccess> getOfferAccess(Offer offer, boolean valid) { StringBuilder sb = new StringBuilder(); sb.append("select access from acofferaccess access") .append(" inner join fetch access.offer offer") .append(" inner join fetch access.method method") .append(" inner join fetch offer.resource resource") .append(" where offer.key=:offerKey") .append(" and access.valid=").append(valid); return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), OfferAccess.class) .setParameter("offerKey", offer.getKey()) .getResultList(); } public List<OfferAccess> getOfferAccess(Collection<Offer> offers, boolean valid) { if(offers == null || offers.isEmpty()) return Collections.emptyList(); StringBuilder sb = new StringBuilder(); sb.append("select access from acofferaccess access") .append(" inner join fetch access.offer offer") .append(" inner join fetch access.method method") .append(" inner join fetch offer.resource resource") .append(" where offer.key in (:offersKey)") .append(" and access.valid=:valid"); List<Long> offersKey = PersistenceHelper.toKeys(offers); return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), OfferAccess.class) .setParameter("offersKey", offersKey) .setParameter("valid", valid) .getResultList(); } public List<OLATResourceAccess> getAccessMethodForResources(Collection<Long> resourceKeys, String resourceType, String excludedResourceType, boolean valid, Date atDate) { final int maxResourcesEntries = 250;//quicker to filter in java, numerous keys in "in" are slow StringBuilder sb = new StringBuilder(); sb.append("select access.method, resource, offer.price from acofferaccess access, ") .append(OLATResourceImpl.class.getName()).append(" resource") .append(" inner join access.offer offer") .append(" inner join offer.resource oResource") .append(" where access.valid=").append(valid).append(" and offer.valid=").append(valid) .append(" and resource.key=oResource.key"); if(resourceKeys != null && !resourceKeys.isEmpty()) { if(resourceKeys.size() < maxResourcesEntries) { sb.append(" and resource.key in (:resourceKeys) "); } sb.append(" and oResource.key=resource.key"); } if(StringHelper.containsNonWhitespace(resourceType)) { sb.append(" and oResource.resName =:resourceType "); } if(StringHelper.containsNonWhitespace(excludedResourceType)) { sb.append(" and not(oResource.resName=:excludedResourceType)"); } if(atDate != null) { sb.append(" and (offer.validFrom is null or offer.validFrom<=:atDate)") .append(" and (offer.validTo is null or offer.validTo>=:atDate)"); } TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Object[].class); if(atDate != null) { query.setParameter("atDate", atDate, TemporalType.TIMESTAMP); } Set<Long> resourceKeysSet = null; if(resourceKeys != null && !resourceKeys.isEmpty()) { if(resourceKeys.size() < maxResourcesEntries) { query.setParameter("resourceKeys", resourceKeys); } else { resourceKeysSet = new HashSet<Long>(resourceKeys); } } if(StringHelper.containsNonWhitespace(resourceType)) { query.setParameter("resourceType", resourceType); } if(StringHelper.containsNonWhitespace(excludedResourceType)) { query.setParameter("excludedResourceType", excludedResourceType); } List<Object[]> rawResults = query.getResultList(); Map<Long,OLATResourceAccess> rawResultsMap = new HashMap<Long,OLATResourceAccess>(); for(Object[] rawResult:rawResults) { AccessMethod method = (AccessMethod)rawResult[0]; OLATResource resource = (OLATResource)rawResult[1]; if(resourceKeysSet != null && !resourceKeysSet.contains(resource.getKey())) { continue; } Price price = (Price)rawResult[2]; if(rawResultsMap.containsKey(resource.getKey())) { rawResultsMap.get(resource.getKey()).addBundle(price, method); } else { rawResultsMap.put(resource.getKey(), new OLATResourceAccess(resource, price, method)); } } return new ArrayList<OLATResourceAccess>(rawResultsMap.values()); } public OfferAccess createOfferAccess(Offer offer, AccessMethod method) { OfferAccessImpl access = new OfferAccessImpl(); access.setCreationDate(new Date()); access.setOffer(offer); access.setMethod(method); access.setValid(true); return access; } public OfferAccess save(OfferAccess link) { if(link.getKey() == null) { dbInstance.getCurrentEntityManager().persist(link); } else { link = dbInstance.getCurrentEntityManager().merge(link); } return link; } public void delete(OfferAccess link) { OfferAccessImpl access = (OfferAccessImpl)link; access.setValid(false); if(link.getKey() == null) return; dbInstance.updateObject(access); } /** * Activate the token method if not already configured. */ protected void activateTokenMethod(boolean enable) { StringBuilder sb = new StringBuilder(); sb.append("select method from actokenmethod method"); List<AccessMethod> methods = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), AccessMethod.class) .getResultList(); if(methods.isEmpty() && enable) { TokenAccessMethod method = new TokenAccessMethod(); method.setCreationDate(new Date()); method.setLastModified(method.getCreationDate()); dbInstance.saveObject(method); } else { for(AccessMethod method:methods) { if(method.isEnabled() != enable) { ((AbstractAccessMethod)method).setEnabled(enable); ((AbstractAccessMethod)method).setLastModified(new Date()); dbInstance.updateObject(method); } } } } protected void activateFreeMethod(boolean enable) { StringBuilder sb = new StringBuilder(); sb.append("select method from ").append(AbstractAccessMethod.class.getName()) .append(" method where method.class=").append(FreeAccessMethod.class.getName()); TypedQuery<AccessMethod> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), AccessMethod.class); List<AccessMethod> methods = query.getResultList(); if(methods.isEmpty() && enable) { FreeAccessMethod method = new FreeAccessMethod(); method.setCreationDate(new Date()); method.setLastModified(method.getCreationDate()); dbInstance.saveObject(method); } else { for(AccessMethod method:methods) { if(method.isEnabled() != enable) { ((AbstractAccessMethod)method).setEnabled(enable); ((AbstractAccessMethod)method).setLastModified(new Date()); dbInstance.updateObject(method); } } } } }