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