001/* 002 * (C) Copyright 2006-2010 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 * Thierry Delprat 018 */ 019package org.nuxeo.apidoc.repository; 020 021import java.io.Serializable; 022import java.util.ArrayList; 023import java.util.Calendar; 024import java.util.Date; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029 030import org.nuxeo.apidoc.adapters.BaseNuxeoArtifactDocAdapter; 031import org.nuxeo.apidoc.api.BundleGroup; 032import org.nuxeo.apidoc.api.BundleInfo; 033import org.nuxeo.apidoc.api.ComponentInfo; 034import org.nuxeo.apidoc.api.ExtensionInfo; 035import org.nuxeo.apidoc.api.ExtensionPointInfo; 036import org.nuxeo.apidoc.api.OperationInfo; 037import org.nuxeo.apidoc.api.QueryHelper; 038import org.nuxeo.apidoc.api.SeamComponentInfo; 039import org.nuxeo.apidoc.api.ServiceInfo; 040import org.nuxeo.apidoc.documentation.JavaDocHelper; 041import org.nuxeo.apidoc.introspection.ServerInfo; 042import org.nuxeo.apidoc.snapshot.DistributionSnapshot; 043import org.nuxeo.common.utils.Path; 044import org.nuxeo.ecm.core.api.CoreSession; 045import org.nuxeo.ecm.core.api.DocumentModel; 046import org.nuxeo.ecm.core.api.DocumentModelList; 047import org.nuxeo.ecm.core.api.DocumentRef; 048import org.nuxeo.ecm.core.api.PathRef; 049import org.nuxeo.ecm.core.api.PropertyException; 050import org.nuxeo.ecm.core.query.sql.NXQL; 051 052public class RepositoryDistributionSnapshot extends BaseNuxeoArtifactDocAdapter implements DistributionSnapshot { 053 054 protected JavaDocHelper jdocHelper = null; 055 056 public static RepositoryDistributionSnapshot create(DistributionSnapshot distrib, CoreSession session, 057 String containerPath, String label, Map<String, Serializable> properties) { 058 DocumentModel doc = session.createDocumentModel(TYPE_NAME); 059 String name = computeDocumentName(distrib.getKey()); 060 if (label != null) { 061 name = computeDocumentName(label); 062 } 063 String targetPath = new Path(containerPath).append(name).toString(); 064 065 boolean exist = false; 066 if (session.exists(new PathRef(targetPath))) { 067 exist = true; 068 doc = session.getDocument(new PathRef(targetPath)); 069 } 070 071 // Set first properties passed by parameter to not override default 072 // behavior 073 if (properties != null) { 074 properties.forEach(doc::setPropertyValue); 075 } 076 077 doc.setPathInfo(containerPath, name); 078 if (label == null) { 079 doc.setPropertyValue("dc:title", distrib.getKey()); 080 doc.setPropertyValue(PROP_KEY, distrib.getKey()); 081 doc.setPropertyValue(PROP_NAME, distrib.getName()); 082 } else { 083 doc.setPropertyValue("dc:title", label); 084 doc.setPropertyValue(PROP_KEY, label + "-" + distrib.getVersion()); 085 doc.setPropertyValue(PROP_NAME, label); 086 } 087 doc.setPropertyValue(PROP_LATEST_FT, distrib.isLatestFT()); 088 doc.setPropertyValue(PROP_LATEST_LTS, distrib.isLatestLTS()); 089 doc.setPropertyValue(PROP_VERSION, distrib.getVersion()); 090 091 DocumentModel ret; 092 if (exist) { 093 ret = session.saveDocument(doc); 094 } else { 095 ret = session.createDocument(doc); 096 } 097 return new RepositoryDistributionSnapshot(ret); 098 } 099 100 public static List<DistributionSnapshot> readPersistentSnapshots(CoreSession session) { 101 List<DistributionSnapshot> result = new ArrayList<>(); 102 String query = "SELECT * FROM " + TYPE_NAME + " where ecm:currentLifeCycleState != 'deleted'"; 103 DocumentModelList docs = session.query(query); 104 for (DocumentModel child : docs) { 105 DistributionSnapshot ob = child.getAdapter(DistributionSnapshot.class); 106 if (ob != null) { 107 result.add(ob); 108 } 109 } 110 return result; 111 } 112 113 public RepositoryDistributionSnapshot(DocumentModel doc) { 114 super(doc); 115 } 116 117 protected <T> List<T> getChildren(Class<T> adapter, String docType) { 118 List<T> result = new ArrayList<>(); 119 String query = QueryHelper.select(docType, doc); 120 DocumentModelList docs = getCoreSession().query(query); 121 for (DocumentModel child : docs) { 122 T ob = child.getAdapter(adapter); 123 if (ob != null) { 124 result.add(ob); 125 } 126 } 127 return result; 128 } 129 130 protected <T> T getChild(Class<T> adapter, String docType, String idField, String id) { 131 String query = QueryHelper.select(docType, doc) + " AND " + idField + " = " + NXQL.escapeString(id); 132 DocumentModelList docs = getCoreSession().query(query); 133 if (docs.isEmpty()) { 134 log.error("Unable to find " + docType + " for id " + id); 135 } else if (docs.size() == 1) { 136 return docs.get(0).getAdapter(adapter); 137 } else { 138 log.error("multiple match for " + docType + " for id " + id); 139 return docs.get(0).getAdapter(adapter); 140 } 141 return null; 142 } 143 144 @Override 145 public BundleInfo getBundle(String id) { 146 return getChild(BundleInfo.class, BundleInfo.TYPE_NAME, BundleInfo.PROP_BUNDLE_ID, id); 147 } 148 149 @Override 150 public BundleGroup getBundleGroup(String groupId) { 151 return getChild(BundleGroup.class, BundleGroup.TYPE_NAME, BundleGroup.PROP_KEY, groupId); 152 } 153 154 protected DocumentModel getBundleContainer() { 155 DocumentRef ref = new PathRef(doc.getPathAsString(), SnapshotPersister.Bundle_Root_NAME); 156 if (getCoreSession().exists(ref)) { 157 return getCoreSession().getDocument(ref); 158 } else { 159 // for compatibility with the previous persistence model 160 return doc; 161 } 162 } 163 164 @Override 165 public List<BundleGroup> getBundleGroups() { 166 List<BundleGroup> grps = new ArrayList<>(); 167 String query = QueryHelper.select(BundleGroup.TYPE_NAME, doc, NXQL.ECM_PARENTID, getBundleContainer().getId()); 168 DocumentModelList docs = getCoreSession().query(query); 169 for (DocumentModel child : docs) { 170 BundleGroup bg = child.getAdapter(BundleGroup.class); 171 if (bg != null) { 172 grps.add(bg); 173 } 174 } 175 return grps; 176 } 177 178 @Override 179 public List<String> getBundleIds() { 180 List<String> ids = new ArrayList<>(); 181 for (BundleInfo bi : getChildren(BundleInfo.class, BundleInfo.TYPE_NAME)) { 182 ids.add(bi.getId()); 183 } 184 return ids; 185 } 186 187 @Override 188 public ComponentInfo getComponent(String id) { 189 return getChild(ComponentInfo.class, ComponentInfo.TYPE_NAME, ComponentInfo.PROP_COMPONENT_ID, id); 190 } 191 192 @Override 193 public List<String> getComponentIds() { 194 List<String> ids = new ArrayList<>(); 195 for (ComponentInfo ci : getChildren(ComponentInfo.class, ComponentInfo.TYPE_NAME)) { 196 ids.add(ci.getId()); 197 } 198 return ids; 199 } 200 201 @Override 202 public ExtensionInfo getContribution(String id) { 203 return getChild(ExtensionInfo.class, ExtensionInfo.TYPE_NAME, ExtensionInfo.PROP_CONTRIB_ID, id); 204 } 205 206 @Override 207 public List<String> getContributionIds() { 208 List<String> ids = new ArrayList<>(); 209 for (ExtensionInfo xi : getChildren(ExtensionInfo.class, ExtensionInfo.TYPE_NAME)) { 210 ids.add(xi.getId()); 211 } 212 return ids; 213 } 214 215 @Override 216 public List<ExtensionInfo> getContributions() { 217 return getChildren(ExtensionInfo.class, ExtensionInfo.TYPE_NAME); 218 } 219 220 @Override 221 public ExtensionPointInfo getExtensionPoint(String id) { 222 return getChild(ExtensionPointInfo.class, ExtensionPointInfo.TYPE_NAME, ExtensionPointInfo.PROP_EP_ID, id); 223 } 224 225 @Override 226 public List<String> getExtensionPointIds() { 227 List<String> ids = new ArrayList<>(); 228 for (ExtensionPointInfo xpi : getChildren(ExtensionPointInfo.class, ExtensionPointInfo.TYPE_NAME)) { 229 ids.add(xpi.getId()); 230 } 231 return ids; 232 } 233 234 @Override 235 public List<String> getBundleGroupChildren(String groupId) { 236 BundleGroup bg = getChild(BundleGroup.class, BundleGroup.TYPE_NAME, BundleGroup.PROP_KEY, groupId); 237 return bg.getBundleIds(); 238 } 239 240 public List<String> getBundleGroupIds() { 241 List<String> ids = new ArrayList<>(); 242 for (BundleGroup bg : getChildren(BundleGroup.class, BundleGroup.TYPE_NAME)) { 243 ids.add(bg.getId()); 244 } 245 return ids; 246 } 247 248 @Override 249 public List<String> getServiceIds() { 250 Set<String> ids = new HashSet<>(); 251 String query = QueryHelper.select(ComponentInfo.TYPE_NAME, doc); 252 DocumentModelList components = getCoreSession().query(query); 253 for (DocumentModel componentDoc : components) { 254 ComponentInfo ci = componentDoc.getAdapter(ComponentInfo.class); 255 if (ci == null) { 256 continue; 257 } 258 ids.addAll(ci.getServiceNames()); 259 } 260 return new ArrayList<>(ids); 261 } 262 263 @Override 264 public String getName() { 265 try { 266 return (String) doc.getPropertyValue(PROP_NAME); 267 } catch (PropertyException e) { 268 log.error("Error while reading nxdistribution:name", e); 269 return "!unknown!"; 270 } 271 } 272 273 @Override 274 public String getVersion() { 275 try { 276 return (String) doc.getPropertyValue(PROP_VERSION); 277 } catch (PropertyException e) { 278 log.error("Error while reading nxdistribution:version", e); 279 return "!unknown!"; 280 } 281 } 282 283 @Override 284 public String getKey() { 285 try { 286 return (String) doc.getPropertyValue(PROP_KEY); 287 } catch (PropertyException e) { 288 log.error("Error while reading nxdistribution:key", e); 289 return "!unknown!"; 290 } 291 } 292 293 @Override 294 public List<Class<?>> getSpi() { 295 return null; 296 } 297 298 @Override 299 public String getId() { 300 return getKey(); 301 } 302 303 @Override 304 public String getArtifactType() { 305 return TYPE_NAME; 306 } 307 308 @Override 309 public ServiceInfo getService(String id) { 310 String query = QueryHelper.select(ServiceInfo.TYPE_NAME, getDoc()) + " AND " + ServiceInfo.PROP_CLASS_NAME 311 + " = " + NXQL.escapeString(id) + " AND " + ServiceInfo.PROP_OVERRIDEN + " = 0"; 312 DocumentModelList docs = getCoreSession().query(query); 313 if (docs.size() > 1) { 314 throw new AssertionError("Multiple services found for " + id); 315 } 316 return docs.get(0).getAdapter(ServiceInfo.class); 317 } 318 319 @Override 320 public List<String> getJavaComponentIds() { 321 List<String> ids = new ArrayList<>(); 322 for (ComponentInfo ci : getChildren(ComponentInfo.class, ComponentInfo.TYPE_NAME)) { 323 if (!ci.isXmlPureComponent()) { 324 ids.add(ci.getId()); 325 } 326 } 327 return ids; 328 } 329 330 @Override 331 public List<String> getXmlComponentIds() { 332 List<String> ids = new ArrayList<>(); 333 for (ComponentInfo ci : getChildren(ComponentInfo.class, ComponentInfo.TYPE_NAME)) { 334 if (ci.isXmlPureComponent()) { 335 ids.add(ci.getId()); 336 } 337 } 338 return ids; 339 } 340 341 @Override 342 public Date getCreationDate() { 343 try { 344 Calendar cal = (Calendar) getDoc().getPropertyValue("dc:created"); 345 return cal == null ? null : cal.getTime(); 346 } catch (PropertyException e) { 347 return null; 348 } 349 } 350 351 @Override 352 public Date getReleaseDate() { 353 try { 354 Calendar cal = (Calendar) getDoc().getPropertyValue("nxdistribution:released"); 355 return cal == null ? getCreationDate() : cal.getTime(); 356 } catch (PropertyException e) { 357 return null; 358 } 359 } 360 361 @Override 362 public boolean isLive() { 363 return false; 364 } 365 366 @Override 367 public SeamComponentInfo getSeamComponent(String id) { 368 String name = id.replace("seam:", ""); 369 String query = QueryHelper.select(SeamComponentInfo.TYPE_NAME, getDoc()) + " AND " 370 + SeamComponentInfo.PROP_COMPONENT_NAME + " = " + NXQL.escapeString(name); 371 DocumentModelList docs = getCoreSession().query(query); 372 return docs.isEmpty() ? null : docs.get(0).getAdapter(SeamComponentInfo.class); 373 } 374 375 @Override 376 public List<String> getSeamComponentIds() { 377 List<String> result = new ArrayList<>(); 378 String query = QueryHelper.select(SeamComponentInfo.TYPE_NAME, getDoc()); 379 DocumentModelList docs = getCoreSession().query(query); 380 for (DocumentModel doc : docs) { 381 result.add(doc.getAdapter(SeamComponentInfo.class).getId()); 382 } 383 return result; 384 } 385 386 @Override 387 public List<SeamComponentInfo> getSeamComponents() { 388 List<SeamComponentInfo> result = new ArrayList<>(); 389 String query = QueryHelper.select(SeamComponentInfo.TYPE_NAME, getDoc()); 390 DocumentModelList docs = getCoreSession().query(query); 391 for (DocumentModel doc : docs) { 392 result.add(doc.getAdapter(SeamComponentInfo.class)); 393 } 394 return result; 395 } 396 397 @Override 398 public boolean containsSeamComponents() { 399 return getSeamComponentIds().size() > 0; 400 } 401 402 @Override 403 public OperationInfo getOperation(String id) { 404 if (id.startsWith(OperationInfo.ARTIFACT_PREFIX)) { 405 id = id.substring(OperationInfo.ARTIFACT_PREFIX.length()); 406 } 407 String query = QueryHelper.select(OperationInfo.TYPE_NAME, getDoc()) + " AND " + OperationInfo.PROP_NAME 408 + " = " + NXQL.escapeString(id); 409 DocumentModelList docs = getCoreSession().query(query); 410 return docs.isEmpty() ? null : docs.get(0).getAdapter(OperationInfo.class); 411 } 412 413 @Override 414 public List<OperationInfo> getOperations() { 415 List<OperationInfo> result = new ArrayList<>(); 416 String query = QueryHelper.select(OperationInfo.TYPE_NAME, getDoc()); 417 DocumentModelList docs = getCoreSession().query(query); 418 for (DocumentModel doc : docs) { 419 result.add(doc.getAdapter(OperationInfo.class)); 420 } 421 // TODO sort 422 return result; 423 } 424 425 public JavaDocHelper getJavaDocHelper() { 426 if (jdocHelper == null) { 427 jdocHelper = JavaDocHelper.getHelper(getName(), getVersion()); 428 } 429 return jdocHelper; 430 } 431 432 @Override 433 public void cleanPreviousArtifacts() { 434 String query = QueryHelper.select("Document", getDoc()); 435 List<DocumentRef> refs = new ArrayList<>(); 436 DocumentModelList docs = getCoreSession().query(query); 437 for (DocumentModel doc : docs) { 438 refs.add(doc.getRef()); 439 } 440 getCoreSession().removeDocuments(refs.toArray(new DocumentRef[refs.size()])); 441 } 442 443 @Override 444 public boolean isLatestFT() { 445 try { 446 return (Boolean) doc.getPropertyValue(PROP_LATEST_FT); 447 } catch (PropertyException e) { 448 log.error("Error while reading nxdistribution:latestFT", e); 449 return false; 450 } 451 } 452 453 @Override 454 public boolean isLatestLTS() { 455 try { 456 return (Boolean) doc.getPropertyValue(PROP_LATEST_LTS); 457 } catch (PropertyException e) { 458 log.error("Error while reading nxdistribution:latestLTS", e); 459 return false; 460 } 461 } 462 463 @Override 464 public List<String> getAliases() { 465 @SuppressWarnings("unchecked") 466 List<String> aliases = (List<String>) doc.getPropertyValue(PROP_ALIASES); 467 if (isLatestLTS()) { 468 aliases.add("latestLTS"); 469 } else if (isLatestFT()) { 470 aliases.add("latestFT"); 471 } 472 return aliases; 473 } 474 475 @Override 476 public boolean isHidden() { 477 return Boolean.TRUE.equals(doc.getPropertyValue(PROP_HIDE)); 478 } 479 480 @Override 481 public ServerInfo getServerInfo() { 482 throw new UnsupportedOperationException(); 483 } 484}