/**
   * @param manager the component manager to use to dynamically register components
   * @param classLoader the classloader to use to look for the Component list declaration file (
   *     {@code META-INF/components.txt})
   * @param componentDeclarations the declarations of components to register
   * @since 4.0M1
   */
  public void unregister(
      ComponentManager manager,
      ClassLoader classLoader,
      List<ComponentDeclaration> componentDeclarations) {
    for (ComponentDeclaration componentDeclaration : componentDeclarations) {
      try {
        for (ComponentDescriptor<?> componentDescriptor :
            getComponentsDescriptors(
                classLoader.loadClass(componentDeclaration.getImplementationClassName()))) {
          manager.unregisterComponent(componentDescriptor);

          if (componentDescriptor.getRoleType() instanceof ParameterizedType) {
            Class roleClass = ReflectionUtils.getTypeClass(componentDescriptor.getRoleType());

            DefaultComponentDescriptor<?> classComponentDescriptor =
                new DefaultComponentDescriptor(componentDescriptor);
            classComponentDescriptor.setRoleType(roleClass);

            manager.unregisterComponent(classComponentDescriptor);
          }
        }
      } catch (ClassNotFoundException e) {
        getLogger()
            .warn(
                "Can't find any existing component with class [{}]. Ignoring it.",
                componentDeclaration.getImplementationClassName());
      }
    }
  }
  // Only do once, because components are stored statically within various classes,
  // which causes problems with changing genetics mocks
  @BeforeClass
  @SuppressWarnings("unchecked")
  public static void setupComponents() throws ComponentLookupException, CacheException {
    ComponentManager componentManager = mock(ComponentManager.class);
    Provider<ComponentManager> mockProvider = mock(Provider.class);
    // This is a bit fragile, let's hope the field name doesn't change
    ReflectionUtils.setFieldValue(new ComponentManagerRegistry(), "cmProvider", mockProvider);
    when(mockProvider.get()).thenReturn(componentManager);

    CacheManager cacheManager = mock(CacheManager.class);
    when(componentManager.getInstance(CacheManager.class)).thenReturn(cacheManager);

    CacheFactory cacheFactory = mock(CacheFactory.class);
    when(cacheManager.getLocalCacheFactory()).thenReturn(cacheFactory);

    Cache<Exome> cache = mock(Cache.class);
    doReturn(cache).when(cacheFactory).newCache(Matchers.any(CacheConfiguration.class));
    doReturn(null).when(cache).get(Matchers.anyString());

    // Wire up mocked genetics
    exomeManager = mock(ExomeManager.class);
    when(componentManager.getInstance(ExomeManager.class, "exomiser")).thenReturn(exomeManager);

    // Use a real GenotypeManager
    PatientGenotypeManager genotypeManager = new DefaultPatientGenotypeManager();
    when(componentManager.getInstance(PatientGenotypeManager.class)).thenReturn(genotypeManager);
  }
  /**
   * Allow to retrieve the total count of items for the given query instead of the actual results.
   * This method will only work for queries selecting document full names, see {@link CountFilter}
   * for more information.
   *
   * @return the total number of results for this query.
   */
  public long count() {
    long result = -1;

    try {
      // Create a copy of the wrapped query.
      QueryManager queryManager = (QueryManager) componentManager.getInstance(QueryManager.class);
      Query countQuery = queryManager.createQuery(getStatement(), getLanguage());
      countQuery.setWiki(getWiki());
      for (Map.Entry<Integer, Object> entry : getPositionalParameters().entrySet()) {
        countQuery.bindValue(entry.getKey(), entry.getValue());
      }
      for (Map.Entry<String, Object> entry : getNamedParameters().entrySet()) {
        countQuery.bindValue(entry.getKey(), entry.getValue());
      }
      for (QueryFilter filter : getFilters()) {
        countQuery.addFilter(filter);
      }

      // Add the count filter to it.
      countQuery.addFilter(componentManager.<QueryFilter>getInstance(QueryFilter.class, "count"));

      // Execute and retrieve the count result.
      List<Long> results = countQuery.execute();
      result = results.get(0);
    } catch (Exception e) {
      LOGGER.warn("Failed to create count query for query [{}]", getStatement());
      e.printStackTrace();
    }

    return result;
  }
 @Override
 public boolean authenticate(String username, Object password) throws Exception {
   boolean isAuthenticated = false;
   ComponentManager componentManager =
       (ComponentManager) getContext().getAttributes().get("componentManager");
   try {
     CrashConfiguration configuration = componentManager.getInstance(CrashConfiguration.class);
     CrashAuthentication authentication =
         componentManager.getInstance(
             CrashAuthentication.class, configuration.getAuthentication());
     isAuthenticated = authentication.authenticate(username, (String) password, getContext());
   } catch (Exception e) {
     // Nothing to do, isAuthenticated is false by default
   }
   return isAuthenticated;
 }
  public ResourceExtensionRepository(
      ClassLoader classLoader, String baseResource, ComponentManager componentManager)
      throws ComponentLookupException {
    super(new ExtensionRepositoryId("test-resources", "resources", null));

    this.extensionSerializer = componentManager.lookup(ExtensionSerializer.class);

    this.classLoader = classLoader;
    this.baseResource = baseResource;
  }
 /**
  * {@inheritDoc}
  *
  * @see
  *     org.xwiki.velocity.VelocityContextInitializer#initialize(org.apache.velocity.VelocityContext)
  */
 public void initialize(VelocityContext context) {
   try {
     // create a wrapper of the annotation service for exposing its methods in velocity
     ScriptService annotationsScriptService =
         componentManager.lookup(ScriptService.class, ANNOTATION_SCRIPT_SERVICE_HINT);
     context.put(VELOCITY_CONTEXT_KEY, annotationsScriptService);
   } catch (ComponentLookupException e) {
     getLogger()
         .warn(
             "Could not initialize the annotations velocity bridge, "
                 + "annotations service will not be accessible in velocity context.");
   }
 }
 /**
  * {@inheritDoc} <br>
  * Implementation which gets all the annotation class objects in the document pointed by the
  * target, and matches their ids against the ids in the passed collection of annotations. If they
  * match, they are updated with the new data in the annotations in annotation.
  *
  * @see org.xwiki.annotation.io.IOService#updateAnnotations(String, java.util.Collection)
  */
 @Override
 public void updateAnnotations(String target, Collection<Annotation> annotations)
     throws IOServiceException {
   try {
     EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT);
     // get the document name from the parsed reference
     String docName = target;
     if (targetReference.getType() == EntityType.DOCUMENT
         || targetReference.getType() == EntityType.OBJECT_PROPERTY) {
       docName = serializer.serialize(targetReference.extractReference(EntityType.DOCUMENT));
     }
     // get the document pointed to by the target
     XWikiContext deprecatedContext = getXWikiContext();
     XWikiDocument document = deprecatedContext.getWiki().getDocument(docName, deprecatedContext);
     List<String> updateNotifs = new ArrayList<String>();
     boolean updated = false;
     for (Annotation annotation : annotations) {
       // parse annotation id as string. If cannot parse, then ignore annotation, is not valid
       int annId = 0;
       try {
         annId = Integer.parseInt(annotation.getId());
       } catch (NumberFormatException e) {
         continue;
       }
       BaseObject object = document.getXObject(configuration.getAnnotationClassReference(), annId);
       if (object == null) {
         continue;
       }
       updated = updateObject(object, annotation, deprecatedContext) || updated;
       updateNotifs.add(annotation.getId());
     }
     if (updated) {
       // set the author of the document to the current user
       document.setAuthor(deprecatedContext.getUser());
       deprecatedContext
           .getWiki()
           .saveDocument(document, "Updated annotations", deprecatedContext);
       // send annotation update notifications for all annotations set to notify for
       ObservationManager observationManager = componentManager.lookup(ObservationManager.class);
       for (String updateNotif : updateNotifs) {
         observationManager.notify(
             new AnnotationUpdatedEvent(docName, updateNotif), document, deprecatedContext);
       }
     }
   } catch (XWikiException e) {
     throw new IOServiceException("An exception has occurred while updating the annotation", e);
   } catch (ComponentLookupException exc) {
     this.logger.warn(
         "Could not get the observation manager to send notifications about the annotation update");
   }
 }
  /**
   * {@inheritDoc} <br>
   * This implementation deletes the annotation object with the object number indicated by {@code
   * annotationID} from the document indicated by {@code target}, if its stored target matches the
   * passed target.
   *
   * @see org.xwiki.annotation.io.IOService#removeAnnotation(String, String)
   */
  @Override
  public void removeAnnotation(String target, String annotationID) throws IOServiceException {
    try {
      if (annotationID == null || target == null) {
        return;
      }

      EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT);
      // get the target identifier and the document name from the parsed reference
      String localTargetId = target;
      String docName = target;
      if (targetReference.getType() == EntityType.DOCUMENT
          || targetReference.getType() == EntityType.OBJECT_PROPERTY) {
        localTargetId = localSerializer.serialize(targetReference);
        docName = serializer.serialize(targetReference.extractReference(EntityType.DOCUMENT));
      }
      // get the document
      XWikiContext deprecatedContext = getXWikiContext();
      XWikiDocument document = deprecatedContext.getWiki().getDocument(docName, deprecatedContext);
      if (document.isNew()) {
        // if the document doesn't exist already skip it
        return;
      }
      // and the document object on it
      BaseObject annotationObject =
          document.getXObject(
              configuration.getAnnotationClassReference(),
              Integer.valueOf(annotationID.toString()));

      // if object exists and its target matches the requested target, delete it
      if (annotationObject != null
          && localTargetId.equals(annotationObject.getStringValue(Annotation.TARGET_FIELD))) {
        document.removeObject(annotationObject);
        document.setAuthor(deprecatedContext.getUser());
        deprecatedContext
            .getWiki()
            .saveDocument(document, "Deleted annotation " + annotationID, deprecatedContext);
        // notify listeners that an annotation was deleted
        ObservationManager observationManager = componentManager.lookup(ObservationManager.class);
        observationManager.notify(
            new AnnotationDeletedEvent(docName, annotationID), document, deprecatedContext);
      }
    } catch (NumberFormatException e) {
      throw new IOServiceException("An exception has occurred while parsing the annotation id", e);
    } catch (XWikiException e) {
      throw new IOServiceException("An exception has occurred while removing the annotation", e);
    } catch (ComponentLookupException exc) {
      this.logger.warn(
          "Could not get the observation manager to send notifications about the annotation delete");
    }
  }
  /**
   * @param manager the component manager to use to dynamically register components
   * @param classLoader the classloader to use to look for the Component list declaration file (
   *     {@code META-INF/components.txt})
   * @param componentDeclarations the declarations of components to register
   * @since 4.0M1
   */
  public void register(
      ComponentManager manager,
      ClassLoader classLoader,
      List<ComponentDeclaration> componentDeclarations) {
    try {
      // 2) For each component class name found, load its class and use introspection to find the
      // necessary
      // annotations required to create a Component Descriptor.
      Map<RoleHint<?>, ComponentDescriptor<?>> descriptorMap =
          new HashMap<RoleHint<?>, ComponentDescriptor<?>>();
      Map<RoleHint<?>, Integer> priorityMap = new HashMap<RoleHint<?>, Integer>();

      for (ComponentDeclaration componentDeclaration : componentDeclarations) {
        Class<?> componentClass =
            classLoader.loadClass(componentDeclaration.getImplementationClassName());

        // Look for ComponentRole annotations and register one component per ComponentRole found
        for (Type componentRoleType : findComponentRoleTypes(componentClass)) {
          for (ComponentDescriptor<?> componentDescriptor :
              this.factory.createComponentDescriptors(componentClass, componentRoleType)) {
            // If there's already a existing role/hint in the list of descriptors then decide which
            // one
            // to keep by looking at their priorities. Highest priority wins (i.e. lowest integer
            // value).
            RoleHint<?> roleHint =
                new RoleHint(componentDescriptor.getRoleType(), componentDescriptor.getRoleHint());

            addComponent(
                descriptorMap,
                priorityMap,
                roleHint,
                componentDescriptor,
                componentDeclaration,
                true);
          }
        }
      }

      // 3) Activate all component descriptors
      for (ComponentDescriptor<?> descriptor : descriptorMap.values()) {
        manager.registerComponent(descriptor);
      }
    } catch (Exception e) {
      // Make sure we make the calling code fail in order to fail fast and prevent the application
      // to start
      // if something is amiss.
      throw new RuntimeException("Failed to dynamically load components with annotations", e);
    }
  }
 /**
  * {@inheritDoc}
  *
  * @throws ComponentLookupException
  * @see org.xwiki.contrib.mail.IMailComponent#getMailReader(java.lang.String, int,
  *     java.lang.String, java.lang.String, java.lang.String, java.util.Properties)
  */
 @Override
 public IMailReader getMailReader(
     final String hostname,
     final int port,
     final String protocol,
     final String username,
     final String password,
     final Properties additionalProperties,
     final Boolean isAutoTrustSslCertificates)
     throws ComponentLookupException {
   final IMailReader reader = componentManager.getInstance(IMailReader.class);
   final ServerAccountSource source =
       new ServerAccountSource(
           hostname,
           port,
           protocol,
           username,
           password,
           additionalProperties,
           isAutoTrustSslCertificates);
   reader.setMailSource(source);
   return reader;
 }
  /**
   * An Event Listener Component has been dynamically registered in the system, add it to our cache.
   *
   * @param event event object containing the new component descriptor
   * @param componentManager the {@link ComponentManager} where the descriptor is registered
   * @param descriptor the component descriptor removed from component manager
   */
  private void onEventListenerComponentAdded(
      ComponentDescriptorAddedEvent event,
      ComponentManager componentManager,
      ComponentDescriptor<EventListener> descriptor) {
    try {
      EventListener eventListener =
          componentManager.getInstance(EventListener.class, event.getRoleHint());

      if (getListener(eventListener.getName()) != eventListener) {
        addListener(eventListener);
      } else {
        this.logger.warn(
            "An Event Listener named [{}] already exists, ignoring the [{}] component",
            eventListener.getName(),
            descriptor.getImplementation().getName());
      }
    } catch (ComponentLookupException e) {
      this.logger.error(
          "Failed to lookup the Event Listener [{}] corresponding to the Component registration "
              + "event for [{}]. Ignoring the event",
          new Object[] {event.getRoleHint(), descriptor.getImplementation().getName(), e});
    }
  }
 /**
  * {@inheritDoc}
  *
  * @see
  *     org.xwiki.contrib.mail.IMailComponent#getMailReader(org.xwiki.contrib.mail.internal.source.ServerAccountSource)
  */
 @Override
 public IMailReader getMailReader(ServerAccountSource source) throws ComponentLookupException {
   final IMailReader reader = componentManager.getInstance(IMailReader.class);
   reader.setMailSource(source);
   return reader;
 }
  /**
   * {@inheritDoc} <br>
   * This implementation saves the added annotation in the document where the target of the
   * annotation is.
   *
   * @see org.xwiki.annotation.io.IOService#addAnnotation(String, org.xwiki.annotation.Annotation)
   */
  @Override
  public void addAnnotation(String target, Annotation annotation) throws IOServiceException {
    try {
      // extract the document name from the passed target
      // by default the fullname is the passed target
      String documentFullName = target;
      EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT);
      // try to get a document reference from the passed target reference
      EntityReference docRef = targetReference.extractReference(EntityType.DOCUMENT);
      if (docRef != null) {
        documentFullName = serializer.serialize(docRef);
      }
      // now get the document with that name
      XWikiContext deprecatedContext = getXWikiContext();
      XWikiDocument document =
          deprecatedContext.getWiki().getDocument(documentFullName, deprecatedContext);
      // create a new object in this document to hold the annotation
      int id =
          document.createXObject(configuration.getAnnotationClassReference(), deprecatedContext);
      BaseObject object = document.getXObject(configuration.getAnnotationClassReference(), id);
      updateObject(object, annotation, deprecatedContext);
      // and set additional data: author to annotation author, date to now and the annotation target
      object.set(Annotation.DATE_FIELD, new Date(), deprecatedContext);
      // TODO: maybe we shouldn't trust what we receive from the caller but set the author from the
      // context.
      // Or the other way around, set the author of the document from the annotations author.
      object.set(Annotation.AUTHOR_FIELD, annotation.getAuthor(), deprecatedContext);
      // store the target of this annotation, serialized with a local serializer, to be exportable
      // and importable
      // in a different wiki
      // TODO: figure out if this is the best idea in terms of target serialization
      // 1/ the good part is that it is a fixed value that can be searched with a query in all
      // objects in the wiki
      // 2/ the bad part is that copying a document to another space will not also update its
      // annotation targets
      // 3/ if annotations are stored in the same document they annotate, the targets are only
      // required for object
      // fields
      // ftm don't store the type of the reference since we only need to recognize the field, not to
      // also read it.
      if (targetReference.getType() == EntityType.OBJECT_PROPERTY
          || targetReference.getType() == EntityType.DOCUMENT) {
        object.set(
            Annotation.TARGET_FIELD, localSerializer.serialize(targetReference), deprecatedContext);
      } else {
        object.set(Annotation.TARGET_FIELD, target, deprecatedContext);
      }
      // set the author of the document to the current user
      document.setAuthor(deprecatedContext.getUser());
      deprecatedContext
          .getWiki()
          .saveDocument(
              document,
              "Added annotation on \"" + annotation.getSelection() + "\"",
              deprecatedContext);

      // notify listeners that an annotation was added
      ObservationManager observationManager = componentManager.lookup(ObservationManager.class);
      observationManager.notify(
          new AnnotationAddedEvent(documentFullName, object.getNumber() + ""),
          document,
          deprecatedContext);

    } catch (XWikiException e) {
      throw new IOServiceException(
          "An exception message has occurred while saving the annotation", e);
    } catch (ComponentLookupException exc) {
      this.logger.warn(
          "Could not get the observation manager to send notifications about the annotation add");
    }
  }