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 <tcardoso@nuxeo.com> 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.getLocalService(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 // restore interrupted status 090 Thread.currentThread().interrupt(); 091 throw new RuntimeException(e); 092 } 093 } 094 automaticLODs = null; 095 automaticRenderViews = null; 096 renderViews = null; 097 } 098 099 @Override 100 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 101 switch (extensionPoint) { 102 case RENDER_VIEWS_EP: 103 renderViews.addContribution((RenderView) contribution); 104 break; 105 case DEFAULT_RENDER_VIEWS_EP: 106 automaticRenderViews.addContribution((AutomaticRenderView) contribution); 107 break; 108 case DEFAULT_LODS_EP: 109 automaticLODs.addContribution((AutomaticLOD) contribution); 110 } 111 } 112 113 @Override 114 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 115 switch (extensionPoint) { 116 case RENDER_VIEWS_EP: 117 renderViews.removeContribution((RenderView) contribution); 118 break; 119 case DEFAULT_RENDER_VIEWS_EP: 120 automaticRenderViews.removeContribution((AutomaticRenderView) contribution); 121 break; 122 case DEFAULT_LODS_EP: 123 automaticLODs.removeContribution((AutomaticLOD) contribution); 124 } 125 } 126 127 @Override 128 public void cleanBatchData(DocumentModel doc) { 129 List<Map<String, Serializable>> emptyList = new ArrayList<>(); 130 doc.setPropertyValue(TRANSMISSIONS_PROPERTY, (Serializable) emptyList); 131 doc.setPropertyValue(RENDER_VIEWS_PROPERTY, (Serializable) emptyList); 132 } 133 134 @Override 135 public void launchBatchConversion(DocumentModel doc) { 136 cleanBatchData(doc); 137 ThreeDBatchUpdateWork work = new ThreeDBatchUpdateWork(doc.getRepositoryName(), doc.getId()); 138 WorkManager workManager = Framework.getLocalService(WorkManager.class); 139 workManager.schedule(work, WorkManager.Scheduling.IF_NOT_SCHEDULED, true); 140 } 141 142 @Override 143 public BlobHolder batchConvert(ThreeD originalThreed) { 144 ConversionService cs = Framework.getService(ConversionService.class); 145 // get all the 3d content blobs 146 List<Blob> in = new ArrayList<>(); 147 in.add(originalThreed.getBlob()); 148 if (originalThreed.getResources() != null) { 149 in.addAll(originalThreed.getResources()); 150 } 151 152 // gather 3D contribution default contributions 153 List<RenderView> renderViews = (List<RenderView>) getAutomaticRenderViews(); 154 List<AutomaticLOD> lods = (List<AutomaticLOD>) getAutomaticLODs(); 155 156 // setup all work to be done in batch process (renders, lods) 157 Map<String, Serializable> params = new HashMap<>(); 158 159 // operators 160 String operators = "import info"; 161 // add renders 162 operators += new String(new char[renderViews.size()]).replace("\0", " render"); 163 // add lods 164 operators += new String(new char[lods.size()]).replace("\0", " lod info convert"); 165 params.put(OPERATORS_PARAMETER, operators); 166 167 // render ids 168 params.put(RENDER_IDS_PARAMETER, renderViews.stream().map(RenderView::getId).collect(Collectors.joining(" "))); 169 170 // lod ids 171 params.put(LOD_IDS_PARAMETER, lods.stream().map(AutomaticLOD::getId).collect(Collectors.joining(" "))); 172 173 // percPoly 174 params.put(PERC_POLY_PARAMETER, 175 lods.stream().map(AutomaticLOD::getPercPoly).map(String::valueOf).collect(Collectors.joining(" "))); 176 177 // maxPoly 178 params.put(MAX_POLY_PARAMETER, 179 lods.stream().map(AutomaticLOD::getMaxPoly).map(String::valueOf).collect(Collectors.joining(" "))); 180 181 params.put(COORDS_PARAMETER, 182 renderViews.stream().map(renderView -> renderView.getAzimuth() + "," + renderView.getZenith()).collect( 183 Collectors.joining(" "))); 184 185 // dimensions 186 params.put(DIMENSIONS_PARAMETER, 187 renderViews.stream().map(renderView -> renderView.getWidth() + "x" + renderView.getHeight()).collect( 188 Collectors.joining(" "))); 189 190 return cs.convert(BATCH_CONVERTER, new SimpleBlobHolder(in), params); 191 } 192 193 @Override 194 public Collection<RenderView> getAvailableRenderViews() { 195 return renderViews.registry.values(); 196 } 197 198 @Override 199 public Collection<RenderView> getAutomaticRenderViews() { 200 return automaticRenderViews.registry.values() 201 .stream() 202 .filter(AutomaticRenderView::isEnabled) 203 .sorted((o1, o2) -> o1.getOrder() - o2.getOrder()) 204 .map(AutomaticRenderView::getId) 205 .map(this::getRenderView) 206 .filter(RenderView::isEnabled) 207 .collect(Collectors.toList()); 208 } 209 210 @Override 211 public Collection<AutomaticLOD> getAvailableLODs() { 212 return automaticLODs.registry.values(); 213 } 214 215 @Override 216 public Collection<AutomaticLOD> getAutomaticLODs() { 217 return automaticLODs.registry.values() 218 .stream() 219 .filter(AutomaticLOD::isEnabled) 220 .sorted((o1, o2) -> o1.getOrder() - o2.getOrder()) 221 .collect(Collectors.toList()); 222 } 223 224 @Override 225 public AutomaticLOD getAutomaticLOD(String automaticLODId) { 226 return automaticLODs.registry.get(automaticLODId); 227 } 228 229 @Override 230 public RenderView getRenderView(String renderViewId) { 231 return renderViews.registry.get(renderViewId); 232 } 233 234 @Override 235 public RenderView getRenderView(Integer azimuth, Integer zenith) { 236 return renderViews.registry.values() 237 .stream() 238 .filter(renderView -> renderView.getAzimuth().equals(azimuth) 239 && renderView.getZenith().equals(zenith)) 240 .findFirst() 241 .orElse(null); 242 } 243 244 @Override 245 public TransmissionThreeD convertColladaToglTF(TransmissionThreeD colladaThreeD) { 246 ConversionService cs = Framework.getService(ConversionService.class); 247 Map<String, Serializable> parameters = new HashMap<>(); 248 List<Blob> blobs = new ArrayList<>(); 249 blobs.add(colladaThreeD.getBlob()); 250 if (colladaThreeD.getResources() != null) { 251 blobs.addAll(colladaThreeD.getResources()); 252 } 253 BlobHolder result = cs.convert(COLLADA2GLTF_CONVERTER, new SimpleBlobHolder(blobs), parameters); 254 return new TransmissionThreeD(result.getBlobs().get(0), null, colladaThreeD.getInfo(), 255 colladaThreeD.getPercPoly(), colladaThreeD.getMaxPoly(), colladaThreeD.getPercTex(), 256 colladaThreeD.getMaxTex(), colladaThreeD.getName()); 257 } 258 259 @Override 260 public ThreeDBatchProgress getBatchProgress(String repositoryName, String docId) { 261 WorkManager workManager = Framework.getLocalService(WorkManager.class); 262 Work work = new ThreeDBatchUpdateWork(repositoryName, docId); 263 Work workRunning = workManager.find(work.getId(), RUNNING); 264 if (workRunning != null) { 265 return new ThreeDBatchProgress(ThreeDBatchProgress.STATUS_CONVERSION_RUNNING, workRunning.getStatus()); 266 } 267 Work workScheduled = workManager.find(work.getId(), SCHEDULED); 268 if (workScheduled != null) { 269 return new ThreeDBatchProgress(ThreeDBatchProgress.STATUS_CONVERSION_QUEUED, ""); 270 } 271 return new ThreeDBatchProgress(ThreeDBatchProgress.STATUS_CONVERSION_UNKNOWN, ""); 272 } 273}