001/* 002 * Copyright 2019 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.odf.ose.export.impl.odf; 017 018import java.util.List; 019import java.util.Optional; 020import java.util.Set; 021 022import org.apache.avalon.framework.component.Component; 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.avalon.framework.service.Serviceable; 026import org.apache.commons.lang3.StringUtils; 027 028import org.ametys.cms.repository.Content; 029import org.ametys.cms.repository.ContentQueryHelper; 030import org.ametys.cms.repository.ContentTypeExpression; 031import org.ametys.cms.repository.LanguageExpression; 032import org.ametys.odf.ProgramItem; 033import org.ametys.odf.enumeration.OdfReferenceTableEntry; 034import org.ametys.odf.orgunit.OrgUnit; 035import org.ametys.odf.ose.db.ParameterizableQuery; 036import org.ametys.odf.ose.export.OSEConstants; 037import org.ametys.odf.ose.export.impl.odf.db.EtapeHelper; 038import org.ametys.odf.ose.export.utils.ElementRetriever; 039import org.ametys.odf.program.Container; 040import org.ametys.odf.program.ContainerFactory; 041import org.ametys.plugins.odfpilotage.helper.PilotageHelper; 042import org.ametys.plugins.repository.AmetysObjectIterable; 043import org.ametys.plugins.repository.AmetysObjectResolver; 044import org.ametys.plugins.repository.EmptyIterable; 045import org.ametys.plugins.repository.query.expression.AndExpression; 046import org.ametys.plugins.repository.query.expression.BooleanExpression; 047import org.ametys.plugins.repository.query.expression.Expression; 048import org.ametys.plugins.repository.query.expression.Expression.Operator; 049import org.ametys.plugins.repository.query.expression.NotExpression; 050import org.ametys.plugins.repository.query.expression.StringExpression; 051import org.ametys.runtime.config.Config; 052import org.ametys.runtime.model.ModelHelper; 053import org.ametys.runtime.plugin.component.AbstractLogEnabled; 054 055/** 056 * Exporter of steps 057 */ 058public class StepExporter extends AbstractLogEnabled implements Component, Serviceable 059{ 060 /** Avalon Role */ 061 public static final String ROLE = StepExporter.class.getName(); 062 063 /** The Ametys object resolver */ 064 protected AmetysObjectResolver _resolver; 065 /** The retriever of elements from ODF */ 066 protected ElementRetriever _elementRetriever; 067 /** The pilotage helper */ 068 protected PilotageHelper _pilotageHelper; 069 070 @Override 071 public void service(ServiceManager manager) throws ServiceException 072 { 073 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 074 _elementRetriever = (ElementRetriever) manager.lookup(ElementRetriever.ROLE); 075 _pilotageHelper = (PilotageHelper) manager.lookup(PilotageHelper.ROLE); 076 } 077 078 /** 079 * Get all the {@link Container} that are steps (nature is "annee") and are exportable (attribute "noOseExport" is not <code>true</code>) 080 * @param ametysCatalog The Ametys catalog 081 * @return The list of exportable steps 082 */ 083 public AmetysObjectIterable<Container> getStepsToExport(String ametysCatalog) 084 { 085 // Add values for steps (container with nature equals to year) 086 return _pilotageHelper.getYearId() 087 .map(anneeId -> _matchingStepsExpression(anneeId, ametysCatalog)) 088 .map(ContentQueryHelper::getContentXPathQuery) 089 .map(_resolver::<Container>query) 090 .orElseGet(EmptyIterable::new); 091 } 092 093 private Expression _matchingStepsExpression(String anneeId, String ametysCatalog) 094 { 095 Expression contentTypeExpr = new ContentTypeExpression(Operator.EQ, ContainerFactory.CONTAINER_CONTENT_TYPE); 096 String lang = Config.getInstance().getValue("odf.programs.lang"); 097 Expression langExpr = new LanguageExpression(Operator.EQ, lang); 098 Expression catalogExpr = new StringExpression(ProgramItem.CATALOG, Operator.EQ, ametysCatalog); 099 Expression natureExpr = new StringExpression(Container.NATURE, Operator.EQ, anneeId); 100 Expression doExportExpression = new NotExpression(new BooleanExpression(OSEConstants.NO_OSE_EXPORT_ATTRIBUTE_NAME, true)); 101 102 return new AndExpression(contentTypeExpr, langExpr, catalogExpr, natureExpr, doExportExpression); 103 } 104 105 /** 106 * Get queries to export the given step. 107 * @param step The step to export 108 * @param oseCatalog The OSE catalog 109 * @return A {@link List} of {@link ParameterizableQuery} to export the {@link Container}, it can be empty if there is a problem (see logs) 110 */ 111 public List<ParameterizableQuery> getQueries(Container step, Long oseCatalog) 112 { 113 // Degree : Remonter aux formations parentes et prendre les degrees, s'il n'y en a qu'une prendre son code, sinon erreur 114 Set<OdfReferenceTableEntry> degrees = _elementRetriever.retrieveDegree(step); 115 116 // Structure : Remonter parent par parent pour obtenir le ou les structures rattachées (sur abstractProgram) 117 Set<OrgUnit> orgUnits = _elementRetriever.retrieveOrgUnits(step); 118 119 if (degrees.size() != 1 || orgUnits.size() != 1) 120 { 121 LogUtils.stepImpossibilityDegreesOrOrgunits(getLogger(), step, degrees, orgUnits); 122 return List.of(); 123 } 124 125 OdfReferenceTableEntry degree = _getFirstDegree(degrees); 126 String degreeCode = degree.getCode(); 127 String orgUnitCode = _getFirstOrgUnitCode(orgUnits); 128 Optional<String> functionalDomain = _getFunctionalDomain(degree); 129 130 if (functionalDomain.isEmpty()) 131 { 132 LogUtils.stepImpossibilityFunctDomain(getLogger(), step); 133 return List.of(); 134 } 135 136 return _getQueries(step, oseCatalog, degreeCode, orgUnitCode, functionalDomain.get()); 137 } 138 139 private Optional<String> _getFunctionalDomain(OdfReferenceTableEntry degree) 140 { 141 Expression expr = new AndExpression( 142 new ContentTypeExpression(Operator.EQ, "odf-enumeration.DegreeCategory"), 143 new StringExpression("degrees", Operator.EQ, degree.getId()) 144 ); 145 146 String xpathQuery = ContentQueryHelper.getContentXPathQuery(expr); 147 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 148 149 return contents 150 .stream() 151 .findFirst() 152 .map(c -> c.<String>getValue("functionalDomain")); 153 } 154 155 private OdfReferenceTableEntry _getFirstDegree(Set<OdfReferenceTableEntry> degrees) 156 { 157 return degrees.stream() 158 .findFirst() 159 .get(); 160 } 161 162 private String _getFirstOrgUnitCode(Set<OrgUnit> orgUnits) 163 { 164 return orgUnits.stream() 165 .findFirst() 166 .map(OrgUnit::getUAICode) 167 .get(); 168 } 169 170 private List<ParameterizableQuery> _getQueries(Container container, Long oseCatalog, String degree, String orgUnit, String functionalDomain) 171 { 172 String title = container.getTitle(); 173 if (ModelHelper.hasModelItem("etpCode", container.getModel())) 174 { 175 String apogee = container.getValue("etpCode"); 176 if (StringUtils.isNotEmpty(apogee)) 177 { 178 title += " (" + apogee + ")"; 179 } 180 } 181 String code = container.getCode(); 182 183 return EtapeHelper.insertInto(code, title, oseCatalog, degree, orgUnit, functionalDomain); 184 } 185} 186