001/* 002 * (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others. 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 * 016 * Contributors: 017 * Tiago Cardoso <[email protected]> 018 */ 019package org.nuxeo.ecm.platform.threed.service; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023import org.nuxeo.ecm.core.api.Blob; 024import org.nuxeo.ecm.core.api.DocumentModel; 025import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 026import org.nuxeo.ecm.core.api.blobholder.SimpleBlobHolder; 027import org.nuxeo.ecm.core.convert.api.ConversionService; 028import org.nuxeo.ecm.core.work.api.Work; 029import org.nuxeo.ecm.core.work.api.WorkManager; 030import org.nuxeo.ecm.platform.threed.ThreeD; 031import org.nuxeo.ecm.platform.threed.ThreeDBatchProgress; 032import org.nuxeo.ecm.platform.threed.TransmissionThreeD; 033import org.nuxeo.runtime.api.Framework; 034import org.nuxeo.runtime.model.ComponentContext; 035import org.nuxeo.runtime.model.ComponentInstance; 036import org.nuxeo.runtime.model.DefaultComponent; 037 038import java.io.Serializable; 039import java.util.ArrayList; 040import java.util.Collection; 041import java.util.HashMap; 042import java.util.List; 043import java.util.Map; 044import java.util.concurrent.TimeUnit; 045import java.util.stream.Collectors; 046 047import static org.nuxeo.ecm.core.work.api.Work.State.*; 048import static org.nuxeo.ecm.platform.threed.ThreeDDocumentConstants.RENDER_VIEWS_PROPERTY; 049import static org.nuxeo.ecm.platform.threed.ThreeDDocumentConstants.TRANSMISSIONS_PROPERTY; 050import static org.nuxeo.ecm.platform.threed.convert.Constants.*; 051 052/** 053 * Default implementation of {@link ThreeDService} 054 * 055 * @since 8.4 056 */ 057public class ThreeDServiceImpl extends DefaultComponent implements ThreeDService { 058 059 protected static final Log log = LogFactory.getLog(ThreeDServiceImpl.class); 060 061 public static final String RENDER_VIEWS_EP = "renderViews"; 062 063 public static final String DEFAULT_RENDER_VIEWS_EP = "automaticRenderViews"; 064 065 public static final String DEFAULT_LODS_EP = "automaticLOD"; 066 067 protected AutomaticLODContributionHandler automaticLODs; 068 069 protected AutomaticRenderViewContributionHandler automaticRenderViews; 070 071 protected RenderViewContributionHandler renderViews; 072 073 @Override 074 public void activate(ComponentContext context) { 075 automaticLODs = new AutomaticLODContributionHandler(); 076 automaticRenderViews = new AutomaticRenderViewContributionHandler(); 077 renderViews = new RenderViewContributionHandler(); 078 } 079 080 @Override 081 public void deactivate(ComponentContext context) { 082 WorkManager workManager = Framework.getService(WorkManager.class); 083 if (workManager != null && workManager.isStarted()) { 084 try { 085 workManager.shutdownQueue( 086 workManager.getCategoryQueueId(ThreeDBatchUpdateWork.CATEGORY_THREED_CONVERSION), 10, 087 TimeUnit.SECONDS); 088 } catch (InterruptedException e) { 089 Thread.currentThread().interrupt(); 090 throw new RuntimeException(e); 091 } 092 } 093 automaticLODs = null; 094 automaticRenderViews = null; 095 renderViews = null; 096 } 097 098 @Override 099 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 100 switch (extensionPoint) { 101 case RENDER_VIEWS_EP: 102 renderViews.addContribution((RenderView) contribution); 103 break; 104 case DEFAULT_RENDER_VIEWS_EP: 105 automaticRenderViews.addContribution((AutomaticRenderView) contribution); 106 break; 107 case DEFAULT_LODS_EP: 108 automaticLODs.addContribution((AutomaticLOD) contribution); 109 } 110 } 111 112 @Override 113 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 114 switch (extensionPoint) { 115 case RENDER_VIEWS_EP: 116 renderViews.removeContribution((RenderView) contribution); 117 break; 118 case DEFAULT_RENDER_VIEWS_EP: 119 automaticRenderViews.removeContribution((AutomaticRenderView) contribution); 120 break; 121 case DEFAULT_LODS_EP: 122 automaticLODs.removeContribution((AutomaticLOD) contribution); 123 } 124 } 125 126 @Override 127 public void cleanBatchData(DocumentModel doc) { 128 List<Map<String, Serializable>> emptyList = new ArrayList<>(); 129 doc.setPropertyValue(TRANSMISSIONS_PROPERTY, (Serializable) emptyList); 130 doc.setPropertyValue(RENDER_VIEWS_PROPERTY, (Serializable) emptyList); 131 } 132 133 @Override 134 public void launchBatchConversion(DocumentModel doc) { 135 cleanBatchData(doc); 136 ThreeDBatchUpdateWork work = new ThreeDBatchUpdateWork(doc.getRepositoryName(), doc.getId()); 137 WorkManager workManager = Framework.getService(WorkManager.class); 138 workManager.schedule(work, WorkManager.Scheduling.IF_NOT_SCHEDULED, true); 139 } 140 141 @Override 142 public BlobHolder batchConvert(ThreeD originalThreed) { 143 ConversionService cs = Framework.getService(ConversionService.class); 144 // get all the 3d content blobs 145 List<Blob> in = new ArrayList<>(); 146 in.add(originalThreed.getBlob()); 147 if (originalThreed.getResources() != null) { 148 in.addAll(originalThreed.getResources()); 149 } 150 151 // gather 3D contribution default contributions 152 List<RenderView> renderViews = (List<RenderView>) getAutomaticRenderViews(); 153 List<AutomaticLOD> lods = (List<AutomaticLOD>) getAutomaticLODs(); 154 155 // setup all work to be done in batch process (renders, lods) 156 Map<String, Serializable> params = new HashMap<>(); 157 158 // operators 159 String operators = "import info"; 160 // add renders 161 operators += new String(new char[renderViews.size()]).replace("\0", " render"); 162 // add lods 163 operators += new String(new char[lods.size()]).replace("\0", " lod info convert"); 164 params.put(OPERATORS_PARAMETER, operators); 165 166 // render ids 167 params.put(RENDER_IDS_PARAMETER, renderViews.stream().map(RenderView::getId).collect(Collectors.joining(" "))); 168 169 // lod ids 170 params.put(LOD_IDS_PARAMETER, lods.stream().map(AutomaticLOD::getId).collect(Collectors.joining(" "))); 171 172 // percPoly 173 params.put(PERC_POLY_PARAMETER, 174 lods.stream().map(AutomaticLOD::getPercPoly).map(String::valueOf).collect(Collectors.joining(" "))); 175 176 // maxPoly 177 params.put(MAX_POLY_PARAMETER, 178 lods.stream().map(AutomaticLOD::getMaxPoly).map(String::valueOf).collect(Collectors.joining(" "))); 179 180 params.put(COORDS_PARAMETER, 181 renderViews.stream().map(renderView -> renderView.getAzimuth() + "," + renderView.getZenith()).collect( 182 Collectors.joining(" "))); 183 184 // dimensions 185 params.put(DIMENSIONS_PARAMETER, 186 renderViews.stream().map(renderView -> renderView.getWidth() + "x" + renderView.getHeight()).collect( 187 Collectors.joining(" "))); 188 189 return cs.convert(BATCH_CONVERTER, new SimpleBlobHolder(in), params); 190 } 191 192 @Override 193 public Collection<RenderView> getAvailableRenderViews() { 194 return renderViews.registry.values(); 195 } 196 197 @Override 198 public Collection<RenderView> getAutomaticRenderViews() { 199 return automaticRenderViews.registry.values() 200 .stream() 201 .filter(AutomaticRenderView::isEnabled) 202 .sorted((o1, o2) -> o1.getOrder() - o2.getOrder()) 203 .map(AutomaticRenderView::getId) 204 .map(this::getRenderView) 205 .filter(RenderView::isEnabled) 206 .collect(Collectors.toList()); 207 } 208 209 @Override 210 public Collection<AutomaticLOD> getAvailableLODs() { 211 return automaticLODs.registry.values(); 212 } 213 214 @Override 215 public Collection<AutomaticLOD> getAutomaticLODs() { 216 return automaticLODs.registry.values() 217 .stream() 218 .filter(AutomaticLOD::isEnabled) 219 .sorted((o1, o2) -> o1.getOrder() - o2.getOrder()) 220 .collect(Collectors.toList()); 221 } 222 223 @Override 224 public AutomaticLOD getAutomaticLOD(String automaticLODId) { 225 return automaticLODs.registry.get(automaticLODId); 226 } 227 228 @Override 229 public RenderView getRenderView(String renderViewId) { 230 return renderViews.registry.get(renderViewId); 231 } 232 233 @Override 234 public RenderView getRenderView(Integer azimuth, Integer zenith) { 235 return renderViews.registry.values() 236 .stream() 237 .filter(renderView -> renderView.getAzimuth().equals(azimuth) 238 && renderView.getZenith().equals(zenith)) 239 .findFirst() 240 .orElse(null); 241 } 242 243 @Override 244 public TransmissionThreeD convertColladaToglTF(TransmissionThreeD colladaThreeD) { 245 ConversionService cs = Framework.getService(ConversionService.class); 246 Map<String, Serializable> parameters = new HashMap<>(); 247 List<Blob> blobs = new ArrayList<>(); 248 blobs.add(colladaThreeD.getBlob()); 249 if (colladaThreeD.getResources() != null) { 250 blobs.addAll(colladaThreeD.getResources()); 251 } 252 BlobHolder result = cs.convert(COLLADA2GLTF_CONVERTER, new SimpleBlobHolder(blobs), parameters); 253 return new TransmissionThreeD(result.getBlobs().get(0), null, colladaThreeD.getInfo(), 254 colladaThreeD.getPercPoly(), colladaThreeD.getMaxPoly(), colladaThreeD.getPercTex(), 255 colladaThreeD.getMaxTex(), colladaThreeD.getName()); 256 } 257 258 @Override 259 public ThreeDBatchProgress getBatchProgress(String repositoryName, String docId) { 260 WorkManager workManager = Framework.getService(WorkManager.class); 261 Work work = new ThreeDBatchUpdateWork(repositoryName, docId); 262 Work workRunning = workManager.find(work.getId(), RUNNING); 263 if (workRunning != null) { 264 return new ThreeDBatchProgress(ThreeDBatchProgress.STATUS_CONVERSION_RUNNING, workRunning.getStatus()); 265 } 266 Work workScheduled = workManager.find(work.getId(), SCHEDULED); 267 if (workScheduled != null) { 268 return new ThreeDBatchProgress(ThreeDBatchProgress.STATUS_CONVERSION_QUEUED, ""); 269 } 270 return new ThreeDBatchProgress(ThreeDBatchProgress.STATUS_CONVERSION_UNKNOWN, ""); 271 } 272}