001/* 002 * (C) Copyright 2006-2010 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Thierry Delprat 016 */ 017package org.nuxeo.apidoc.introspection; 018 019import java.util.ArrayList; 020import java.util.Collections; 021import java.util.Date; 022import java.util.HashMap; 023import java.util.List; 024import java.util.Map; 025 026import javax.servlet.http.HttpServletRequest; 027 028import org.nuxeo.apidoc.api.BaseNuxeoArtifact; 029import org.nuxeo.apidoc.api.BundleGroup; 030import org.nuxeo.apidoc.api.BundleGroupFlatTree; 031import org.nuxeo.apidoc.api.BundleGroupTreeHelper; 032import org.nuxeo.apidoc.api.ComponentInfo; 033import org.nuxeo.apidoc.api.ExtensionInfo; 034import org.nuxeo.apidoc.api.ExtensionPointInfo; 035import org.nuxeo.apidoc.api.OperationInfo; 036import org.nuxeo.apidoc.api.SeamComponentInfo; 037import org.nuxeo.apidoc.api.ServiceInfo; 038import org.nuxeo.apidoc.documentation.JavaDocHelper; 039import org.nuxeo.apidoc.seam.SeamRuntimeIntrospector; 040import org.nuxeo.apidoc.snapshot.DistributionSnapshot; 041import org.nuxeo.ecm.automation.AutomationService; 042import org.nuxeo.ecm.automation.OperationDocumentation; 043import org.nuxeo.ecm.automation.OperationException; 044import org.nuxeo.ecm.automation.OperationType; 045import org.nuxeo.ecm.core.api.NuxeoException; 046import org.nuxeo.runtime.api.Framework; 047 048public class RuntimeSnapshot extends BaseNuxeoArtifact implements DistributionSnapshot { 049 050 public static final String VIRTUAL_BUNDLE_GROUP = "grp:org.nuxeo.misc"; 051 052 protected ServerInfo serverInfo; 053 054 protected Date created; 055 056 protected final List<String> bundlesIds = new ArrayList<String>(); 057 058 protected final List<String> javaComponentsIds = new ArrayList<String>(); 059 060 protected final Map<String, String> components2Bundles = new HashMap<String, String>(); 061 062 protected final Map<String, String> services2Components = new HashMap<String, String>(); 063 064 protected final Map<String, ExtensionPointInfo> extensionPoints = new HashMap<String, ExtensionPointInfo>(); 065 066 protected final Map<String, ExtensionInfo> contributions = new HashMap<String, ExtensionInfo>(); 067 068 protected final Map<String, List<String>> mavenGroups = new HashMap<String, List<String>>(); 069 070 protected final Map<String, List<String>> mavenSubGroups = new HashMap<String, List<String>>(); 071 072 protected final List<BundleGroup> bundleGroups = new ArrayList<BundleGroup>(); 073 074 protected boolean seamInitialized = false; 075 076 protected List<SeamComponentInfo> seamComponents = new ArrayList<SeamComponentInfo>(); 077 078 protected boolean opsInitialized = false; 079 080 protected final List<OperationInfo> operations = new ArrayList<OperationInfo>(); 081 082 protected JavaDocHelper jdocHelper; 083 084 protected final List<Class<?>> spi = new ArrayList<Class<?>>(); 085 086 public RuntimeSnapshot() { 087 buildServerInfo(); 088 } 089 090 @Override 091 public String getVersion() { 092 return serverInfo.getVersion(); 093 } 094 095 @Override 096 public String getName() { 097 return serverInfo.getName(); 098 } 099 100 protected synchronized ServerInfo buildServerInfo() { 101 if (serverInfo == null) { 102 serverInfo = ServerInfo.build(); 103 created = new Date(); 104 spi.addAll(serverInfo.getAllSpi()); 105 for (BundleInfoImpl bInfo : serverInfo.getBundles()) { 106 bundlesIds.add(bInfo.getId()); 107 108 String groupId = bInfo.getArtifactGroupId(); 109 if (groupId != null) { 110 groupId = "grp:" + groupId; 111 } 112 String artifactId = bInfo.getArtifactId(); 113 114 if (groupId == null || artifactId == null) { 115 groupId = VIRTUAL_BUNDLE_GROUP; 116 bInfo.setGroupId(groupId); 117 } 118 if (!mavenGroups.containsKey(groupId)) { 119 mavenGroups.put(groupId, new ArrayList<String>()); 120 } 121 mavenGroups.get(groupId).add(bInfo.getId()); 122 123 for (ComponentInfo cInfo : bInfo.getComponents()) { 124 components2Bundles.put(cInfo.getId(), bInfo.getId()); 125 if (!cInfo.isXmlPureComponent()) { 126 javaComponentsIds.add(cInfo.getId()); 127 } 128 129 for (String serviceName : cInfo.getServiceNames()) { 130 services2Components.put(serviceName, cInfo.getId()); 131 } 132 133 for (ExtensionPointInfo epi : cInfo.getExtensionPoints()) { 134 extensionPoints.put(epi.getId(), epi); 135 } 136 137 for (ExtensionInfo ei : cInfo.getExtensions()) { 138 contributions.put(ei.getId(), ei); 139 } 140 } 141 } 142 } 143 144 // post process bundle groups 145 List<String> mvnGroupNames = new ArrayList<String>(); 146 mvnGroupNames.addAll(mavenGroups.keySet()); 147 148 for (String mvnGroupName : mvnGroupNames) { 149 List<String> artifactIds = mavenGroups.get(mvnGroupName); 150 Collections.sort(artifactIds); 151 152 List<String> subGroups = new ArrayList<String>(); 153 154 for (String id : artifactIds) { 155 if (id.endsWith(".api")) { 156 String grp = "grp:" + id.substring(0, id.length() - 4); 157 158 if (grp.equals(mvnGroupName)) { 159 continue; 160 } 161 162 subGroups.add(grp); 163 } 164 } 165 166 if (subGroups.size() < 2) { 167 // no need to split the maven group into subGroups 168 } else { 169 for (String grp : subGroups) { 170 List<String> grpArtifactIds = new ArrayList<String>(); 171 for (String aid : artifactIds) { 172 if (aid.startsWith(grp) || ("grp:" + aid).startsWith(grp)) { 173 grpArtifactIds.add(aid); 174 } 175 } 176 if (grpArtifactIds.size() > 0) { 177 for (String aid : grpArtifactIds) { 178 artifactIds.remove(aid); 179 } 180 mavenSubGroups.put(grp, grpArtifactIds); 181 artifactIds.add(grp); 182 } 183 } 184 } 185 } 186 187 for (String grpId : mavenGroups.keySet()) { 188 BundleGroupImpl bGroup = buildBundleGroup(grpId, serverInfo.getVersion()); 189 bundleGroups.add(bGroup); 190 } 191 return serverInfo; 192 } 193 194 protected BundleGroupImpl buildBundleGroup(String id, String version) { 195 BundleGroupImpl bGroup = new BundleGroupImpl(id, version); 196 for (String aid : getBundleGroupChildren(id)) { 197 if (aid.startsWith("grp:")) { 198 BundleGroupImpl newGroup = buildBundleGroup(aid, version); 199 bGroup.add(newGroup); 200 newGroup.addParent(bGroup.getId()); 201 } else { 202 bGroup.add(aid); 203 getBundle(aid).setBundleGroup(bGroup); 204 BundleInfoImpl bi = getBundle(aid); 205 bGroup.addLiveDoc(bi.getParentLiveDoc()); 206 } 207 } 208 return bGroup; 209 } 210 211 @Override 212 public List<BundleGroup> getBundleGroups() { 213 return bundleGroups; 214 } 215 216 @Override 217 public BundleGroup getBundleGroup(String groupId) { 218 BundleGroupTreeHelper bgth = new BundleGroupTreeHelper(this); 219 List<BundleGroupFlatTree> tree = bgth.getBundleGroupTree(); 220 221 for (BundleGroupFlatTree info : tree) { 222 if (info.getGroup().getId().equals(groupId)) { 223 return info.getGroup(); 224 } 225 } 226 if (!groupId.startsWith("grp:")) { 227 return getBundleGroup("grp:" + groupId); 228 } 229 return null; 230 } 231 232 protected void browseBundleGroup(BundleGroup group, int level, List<BundleGroupFlatTree> tree) { 233 BundleGroupFlatTree info = new BundleGroupFlatTree(group, level); 234 tree.add(info); 235 236 for (BundleGroup subGroup : group.getSubGroups()) { 237 browseBundleGroup(subGroup, level + 1, tree); 238 } 239 } 240 241 @Override 242 public List<String> getBundleIds() { 243 List<String> bundlesIds = new ArrayList<String>(); 244 245 for (BundleInfoImpl info : serverInfo.getBundles()) { 246 bundlesIds.add(info.getId()); 247 248 } 249 Collections.sort(bundlesIds); 250 return bundlesIds; 251 } 252 253 @Override 254 public BundleInfoImpl getBundle(String id) { 255 return serverInfo.getBundle(id); 256 } 257 258 @Override 259 public List<String> getComponentIds() { 260 List<String> componentsIds = new ArrayList<String>(); 261 componentsIds.addAll(components2Bundles.keySet()); 262 Collections.sort(componentsIds); 263 return componentsIds; 264 } 265 266 @Override 267 public ComponentInfo getComponent(String id) { 268 String bundleId = components2Bundles.get(id); 269 if (bundleId == null) { 270 return null; 271 } 272 BundleInfoImpl bi = getBundle(bundleId); 273 274 for (ComponentInfo ci : bi.getComponents()) { 275 if (ci.getId().equals(id)) { 276 return ci; 277 } 278 } 279 return null; 280 } 281 282 @Override 283 public List<String> getServiceIds() { 284 List<String> serviceIds = new ArrayList<String>(); 285 serviceIds.addAll(services2Components.keySet()); 286 Collections.sort(serviceIds); 287 return serviceIds; 288 } 289 290 @Override 291 public List<String> getExtensionPointIds() { 292 List<String> epIds = new ArrayList<String>(); 293 epIds.addAll(extensionPoints.keySet()); 294 Collections.sort(epIds); 295 return epIds; 296 } 297 298 @Override 299 public ExtensionPointInfo getExtensionPoint(String id) { 300 return extensionPoints.get(id); 301 } 302 303 @Override 304 public List<String> getContributionIds() { 305 List<String> contribIds = new ArrayList<String>(); 306 contribIds.addAll(contributions.keySet()); 307 Collections.sort(contribIds); 308 return contribIds; 309 } 310 311 @Override 312 public List<ExtensionInfo> getContributions() { 313 List<ExtensionInfo> contribs = new ArrayList<ExtensionInfo>(); 314 contribs.addAll(contributions.values()); 315 // TODO sort 316 return contribs; 317 } 318 319 @Override 320 public ExtensionInfo getContribution(String id) { 321 return contributions.get(id); 322 } 323 324 public List<String> getBundleGroupIds() { 325 List<String> grpIds = new ArrayList<String>(); 326 grpIds.addAll(mavenGroups.keySet()); 327 Collections.sort(grpIds); 328 return grpIds; 329 } 330 331 @Override 332 public List<String> getBundleGroupChildren(String groupId) { 333 List<String> res = mavenSubGroups.get(groupId); 334 if (res == null) { 335 // String grpId = groupId.substring(4); 336 res = mavenGroups.get(groupId); 337 } 338 339 if (res != null) { 340 return res; 341 } else { 342 return new ArrayList<String>(); 343 } 344 } 345 346 @Override 347 public String getKey() { 348 return getName() + "-" + getVersion(); 349 } 350 351 @Override 352 public List<Class<?>> getSpi() { 353 return spi; 354 } 355 356 @Override 357 public String getId() { 358 return getKey(); 359 } 360 361 @Override 362 public String getArtifactType() { 363 return TYPE_NAME; 364 } 365 366 @Override 367 public ServiceInfo getService(String id) { 368 String cId = services2Components.get(id); 369 if (cId == null) { 370 return null; 371 } 372 373 for (ServiceInfo si : getComponent(cId).getServices()) { 374 if (id.equals(si.getId())) { 375 return si; 376 } 377 } 378 return null; 379 } 380 381 @Override 382 public List<String> getJavaComponentIds() { 383 return javaComponentsIds; 384 } 385 386 @Override 387 public List<String> getXmlComponentIds() { 388 List<String> result = new ArrayList<String>(); 389 390 for (String cId : getComponentIds()) { 391 if (!javaComponentsIds.contains(cId)) { 392 result.add(cId); 393 } 394 } 395 return result; 396 } 397 398 @Override 399 public Date getCreationDate() { 400 return created; 401 } 402 403 @Override 404 public boolean isLive() { 405 return true; 406 } 407 408 @Override 409 public String getHierarchyPath() { 410 // TODO Auto-generated method stub 411 return null; 412 } 413 414 public void initSeamComponents(HttpServletRequest request) { 415 if (seamInitialized) { 416 return; 417 } 418 seamComponents = SeamRuntimeIntrospector.listNuxeoComponents(request); 419 for (SeamComponentInfo seamComp : seamComponents) { 420 ((SeamComponentInfoImpl) seamComp).setVersion(getVersion()); 421 } 422 seamInitialized = true; 423 } 424 425 public void initOperations() { 426 if (opsInitialized) { 427 return; 428 } 429 OperationType[] ops = Framework.getService(AutomationService.class).getOperations(); 430 for (OperationType op : ops) { 431 OperationDocumentation documentation; 432 try { 433 documentation = op.getDocumentation(); 434 } catch (OperationException e) { 435 throw new NuxeoException(e); 436 } 437 operations.add(new OperationInfoImpl(documentation, getVersion(), op.getType().getCanonicalName(), 438 op.getContributingComponent())); 439 } 440 opsInitialized = true; 441 } 442 443 @Override 444 public SeamComponentInfo getSeamComponent(String id) { 445 for (SeamComponentInfo sci : getSeamComponents()) { 446 if (sci.getId().equals(id)) { 447 return sci; 448 } 449 } 450 return null; 451 } 452 453 @Override 454 public List<String> getSeamComponentIds() { 455 List<String> ids = new ArrayList<String>(); 456 for (SeamComponentInfo sci : getSeamComponents()) { 457 ids.add(sci.getId()); 458 } 459 return ids; 460 } 461 462 @Override 463 public List<SeamComponentInfo> getSeamComponents() { 464 return seamComponents; 465 } 466 467 @Override 468 public boolean containsSeamComponents() { 469 return seamInitialized && getSeamComponentIds().size() > 0; 470 } 471 472 @Override 473 public OperationInfo getOperation(String id) { 474 if (id.startsWith(OperationInfo.ARTIFACT_PREFIX)) { 475 id = id.substring(OperationInfo.ARTIFACT_PREFIX.length()); 476 } 477 for (OperationInfo op : getOperations()) { 478 if (op.getName().equals(id)) { 479 return op; 480 } 481 } 482 return null; 483 } 484 485 @Override 486 public List<OperationInfo> getOperations() { 487 initOperations(); 488 return operations; 489 } 490 491 @Override 492 public JavaDocHelper getJavaDocHelper() { 493 if (jdocHelper == null) { 494 jdocHelper = JavaDocHelper.getHelper(getName(), getVersion()); 495 } 496 return jdocHelper; 497 } 498 499 @Override 500 public void cleanPreviousArtifacts() { 501 // Can't delete anything in a runtime Snapshot 502 throw new UnsupportedOperationException(); 503 } 504}