/**
   * Helper function to load an annotation object from an xwiki object.
   *
   * @param object the xwiki object to load an annotation from
   * @param deprecatedContext XWikiContext to make operations on xwiki data
   * @return the Annotation instance for the annotation stored in BaseObject
   */
  protected Annotation loadAnnotationFromObject(BaseObject object, XWikiContext deprecatedContext) {
    // load the annotation with its ID, special handling of the state since it needs
    // deserialization, special
    // handling of the original selection which shouldn't be set if it's empty
    Annotation annotation = new Annotation(object.getNumber() + "");
    annotation.setState(AnnotationState.valueOf(object.getStringValue(Annotation.STATE_FIELD)));
    String originalSelection = object.getStringValue(Annotation.ORIGINAL_SELECTION_FIELD);
    if (originalSelection != null && originalSelection.length() > 0) {
      annotation.setOriginalSelection(originalSelection);
    }

    Collection<String> skippedFields =
        Arrays.asList(new String[] {Annotation.ORIGINAL_SELECTION_FIELD, Annotation.STATE_FIELD});
    // go through all props and load them in the annotation, except for the ones already loaded
    // get all the props, filter those that need to be skipped and save the rest
    for (String propName : object.getPropertyNames()) {
      if (!skippedFields.contains(propName)) {
        try {
          annotation.set(propName, ((BaseProperty) object.get(propName)).getValue());
        } catch (XWikiException e) {
          this.logger.warn(
              "Unable to get property "
                  + propName
                  + " from object "
                  + object.getClassName()
                  + "["
                  + object.getNumber()
                  + "]. Will not be saved in the annotation.",
              e);
        }
      }
    }
    return annotation;
  }
Example #2
0
  /**
   * Send redirection based on a regexp pattern (if any) set at the main wiki level. To enable this
   * feature you must add xwiki.preferences.redirect=1 to your xwiki.cfg.
   *
   * @param response the servlet response
   * @param url url of the request
   * @param context the XWiki context
   * @return true if a redirection has been sent
   */
  protected boolean sendGlobalRedirect(XWikiResponse response, String url, XWikiContext context)
      throws Exception {
    if ("1".equals(context.getWiki().Param("xwiki.preferences.redirect"))) {
      // Note: This implementation is not performant at all and will slow down the wiki as the
      // number
      // of redirects increases. A better implementation would use a cache of redirects and would
      // use
      // the notification mechanism to update the cache when the XWiki.XWikiPreferences document is
      // modified.
      XWikiDocument globalPreferences =
          context.getWiki().getDocument("xwiki:XWiki.XWikiPreferences", context);
      Vector<BaseObject> redirects = globalPreferences.getObjects("XWiki.GlobalRedirect");

      if (redirects != null) {
        for (BaseObject redir : redirects) {
          if (redir != null) {
            String p = redir.getStringValue("pattern");
            if (p != null && url.matches(p)) {
              String dest = redir.getStringValue("destination");
              response.sendRedirect(url.replaceAll(p, dest));
              return true;
            }
          }
        }
      }
    }
    return false;
  }
  private Map<AccessLevel, List<DocumentReference>> getCollaborators(XWikiDocument doc) {
    Map<AccessLevel, List<DocumentReference>> collaborators =
        new LinkedHashMap<AccessLevel, List<DocumentReference>>();
    List<BaseObject> collaboratorObjects = doc.getXObjects(Collaborator.CLASS_REFERENCE);
    if (collaboratorObjects == null || collaboratorObjects.isEmpty()) {
      return Collections.emptyMap();
    }
    for (BaseObject collaborator : collaboratorObjects) {
      if (collaborator == null) {
        continue;
      }
      String collaboratorName = collaborator.getStringValue("collaborator");
      String accessName = collaborator.getStringValue("access");

      if (StringUtils.isBlank(collaboratorName) || StringUtils.isBlank(accessName)) {
        continue;
      }
      DocumentReference userOrGroup =
          this.stringEntityResolver.resolve(collaboratorName, doc.getDocumentReference());
      AccessLevel access = this.manager.resolveAccessLevel(accessName);
      List<DocumentReference> list = collaborators.get(access);
      if (list == null) {
        list = new LinkedList<DocumentReference>();
        collaborators.put(access, list);
      }
      list.add(userOrGroup);
    }
    return collaborators;
  }
  @Test
  public void getMembersWhenGroupIsLooping() throws Exception {
    setUpBaseMocks();

    DocumentReference groupReference = new DocumentReference("groupwiki", "XWiki", "grouppage");
    XWikiDocument document = mock(XWikiDocument.class);
    when(document.isNew()).thenReturn(false);
    when(document.getDocumentReference()).thenReturn(groupReference);
    when(xwiki.getDocument(groupReference, this.xwikiContext)).thenReturn(document);

    List<BaseObject> memberObjects = new ArrayList<>();
    BaseObject bo = mock(BaseObject.class);
    when(bo.getStringValue("member")).thenReturn("XWiki.othergroup");
    memberObjects.add(bo);
    bo = mock(BaseObject.class);
    when(bo.getStringValue("member")).thenReturn("XWiki.userpage");
    memberObjects.add(bo);
    when(document.getXObjects(new DocumentReference("groupwiki", "XWiki", "XWikiGroups")))
        .thenReturn(memberObjects);

    DocumentReference userpageReference = new DocumentReference("groupwiki", "XWiki", "userpage");
    setUpUserPageMocks(userpageReference);
    when(this.resolver.resolve("XWiki.userpage", groupReference)).thenReturn(userpageReference);

    DocumentReference otherGroupReference =
        new DocumentReference("groupwiki", "XWiki", "othergroup");
    document = mock(XWikiDocument.class);
    when(document.isNew()).thenReturn(false);
    when(document.getDocumentReference()).thenReturn(otherGroupReference);
    when(xwiki.getDocument(otherGroupReference, this.xwikiContext)).thenReturn(document);

    memberObjects = new ArrayList<>();
    bo = mock(BaseObject.class);
    when(bo.getStringValue("member")).thenReturn("XWiki.grouppage");
    memberObjects.add(bo);
    bo = mock(BaseObject.class);
    when(bo.getStringValue("member")).thenReturn("XWiki.anotheruser");
    memberObjects.add(bo);
    when(document.getXObjects(new DocumentReference("groupwiki", "XWiki", "XWikiGroups")))
        .thenReturn(memberObjects);

    DocumentReference anotheruserReference =
        new DocumentReference("groupwiki", "XWiki", "anotheruser");
    setUpUserPageMocks(anotheruserReference);
    when(this.resolver.resolve("XWiki.anotheruser", otherGroupReference))
        .thenReturn(anotheruserReference);

    when(this.resolver.resolve("XWiki.grouppage", otherGroupReference)).thenReturn(groupReference);
    when(this.resolver.resolve("XWiki.othergroup", groupReference)).thenReturn(otherGroupReference);

    Iterator<DocumentReference> iterator =
        new ReferenceUserIterator(groupReference, this.resolver, this.execution);

    assertThat(
        (List<DocumentReference>) IteratorUtils.toList(iterator),
        containsInAnyOrder(userpageReference, anotheruserReference));
  }
  @Test
  public void onEvent() throws ComponentLookupException, XWikiException {
    Utils.setComponentManager(this.mocker);

    DocumentReference docReference = new DocumentReference("xwiki", "Groups", "Group1");
    XWikiContext context = mock(XWikiContext.class);
    XWiki xwiki = mock(XWiki.class);
    when(context.getWiki()).thenReturn(xwiki);

    XWikiDocument doc = mock(XWikiDocument.class);
    when(doc.getDocumentReference()).thenReturn(docReference);
    BaseObject groupObject = new BaseObject();
    BaseObject rightsObject = new BaseObject();
    when(doc.newXObject(eq(this.groupsClassReference), eq(context))).thenReturn(groupObject);
    when(doc.newXObject(eq(this.rightsClassReference), eq(context))).thenReturn(rightsObject);
    when(doc.getXObject(Group.CLASS_REFERENCE)).thenReturn(mock(BaseObject.class));

    DocumentReference adminsDocReference =
        new DocumentReference("xwiki", "Groups", "Group1 Administrators");
    XWikiDocument adminsDoc = mock(XWikiDocument.class);
    BaseObject adminsGroupObject = new BaseObject();
    BaseObject adminsRightsObject = new BaseObject();
    when(adminsDoc.newXObject(eq(this.groupsClassReference), eq(context)))
        .thenReturn(adminsGroupObject);
    when(adminsDoc.newXObject(eq(this.rightsClassReference), eq(context)))
        .thenReturn(adminsRightsObject);
    when(xwiki.getDocument(eq(adminsDocReference), eq(context))).thenReturn(adminsDoc);

    DocumentAccessBridge dab = this.mocker.getInstance(DocumentAccessBridge.class);

    DocumentReference userReference = new DocumentReference("xwiki", "XWiki", "User");
    when(dab.getCurrentUserReference()).thenReturn(userReference);

    this.mocker
        .getComponentUnderTest()
        .onEvent(new DocumentCreatingEvent(docReference), doc, context);

    Mockito.verify(xwiki).saveDocument(eq(adminsDoc), any(String.class), eq(true), eq(context));
    Mockito.verify(xwiki, Mockito.never())
        .saveDocument(eq(doc), any(String.class), any(Boolean.class), eq(context));

    Assert.assertEquals(1, rightsObject.getIntValue("allow"));
    Assert.assertEquals("edit", rightsObject.getStringValue("levels"));
    Assert.assertEquals(
        "xwiki:Groups.Group1 Administrators", rightsObject.getLargeStringValue("groups"));
    Assert.assertEquals("", rightsObject.getLargeStringValue("users"));

    Assert.assertEquals(1, adminsRightsObject.getIntValue("allow"));
    Assert.assertEquals("edit", adminsRightsObject.getStringValue("levels"));
    Assert.assertEquals(
        "xwiki:Groups.Group1 Administrators", adminsRightsObject.getLargeStringValue("groups"));
    Assert.assertEquals("", adminsRightsObject.getLargeStringValue("users"));

    Assert.assertEquals("xwiki:Groups.Group1 Administrators", groupObject.getStringValue("member"));
    Assert.assertEquals("xwiki:XWiki.User", adminsGroupObject.getStringValue("member"));
  }
 @Override
 public PatientData<String> load(Patient patient) {
   try {
     XWikiDocument doc =
         (XWikiDocument) this.documentAccessBridge.getDocument(patient.getDocument());
     BaseObject data = doc.getXObject(Patient.CLASS_REFERENCE);
     if (data == null) {
       return null;
     }
     Map<String, String> result = new LinkedHashMap<>();
     for (String propertyName : getProperties()) {
       String value = data.getStringValue(propertyName);
       if (StringUtils.isNotBlank(value)) {
         result.put(propertyName, value);
       }
     }
     return new DictionaryPatientData<>(getName(), result);
   } catch (Exception e) {
     this.logger.error(
         "Could not find requested document or some unforeseen"
             + " error has occurred during controller loading ",
         e.getMessage());
   }
   return null;
 }
  @Test
  public void getMembersWhenSingleUserButBothUserAndGroupReference() throws Exception {
    setUpBaseMocks();
    DocumentReference reference = new DocumentReference("wiki", "XWiki", "page");

    XWikiDocument document = mock(XWikiDocument.class);
    when(document.isNew()).thenReturn(false);
    when(document.getDocumentReference()).thenReturn(reference);
    when(this.xwiki.getDocument(reference, this.xwikiContext)).thenReturn(document);

    // It's a user reference
    BaseObject bo1 = mock(BaseObject.class);
    when(document.getXObject(new DocumentReference("wiki", "XWiki", "XWikiUsers"))).thenReturn(bo1);

    // It's also a group reference (with one user in it)
    List<BaseObject> memberObjects = new ArrayList<>();
    BaseObject bo2 = mock(BaseObject.class);
    when(bo2.getStringValue("member")).thenReturn("XWiki.user");
    memberObjects.add(bo2);
    when(document.getXObjects(new DocumentReference("wiki", "XWiki", "XWikiGroups")))
        .thenReturn(memberObjects);
    DocumentReference userReference = new DocumentReference("wiki", "XWiki", "user");
    when(this.resolver.resolve("XWiki.user", reference)).thenReturn(userReference);
    setUpUserPageMocks(userReference);

    Iterator<DocumentReference> iterator =
        new ReferenceUserIterator(reference, this.resolver, this.execution);

    assertTrue(iterator.hasNext());
    assertEquals(new DocumentReference("wiki", "XWiki", "page"), iterator.next());
    assertTrue(iterator.hasNext());
    assertEquals(new DocumentReference("wiki", "XWiki", "user"), iterator.next());
    assertFalse(iterator.hasNext());
  }
Example #8
0
  /**
   * Check if the password passed as argument is the user password. This method is used when a user
   * wants to change its password. To make sure that it wouldn't be used to perform brute force
   * attacks, we ensure that this is only used to check the current user password on its profile
   * page.
   *
   * @param password Password submitted.
   * @return true if password is really the user password.
   * @throws XWikiException error if authorization denied.
   */
  public boolean checkPassword(String password) throws XWikiException {
    EntityReference userReference = REFERENCE_RESOLVER.resolve(this.user.getUser());
    EntityReference docReference = getXWikiContext().getDoc().getDocumentReference();
    if (userReference.equals(getXWikiContext().getUserReference())
        && userReference.equals(docReference)) {
      try {
        boolean result = false;

        XWikiDocument userDoc =
            getXWikiContext().getWiki().getDocument(userReference, getXWikiContext());
        BaseObject obj = userDoc.getXObject(USERCLASS_REFERENCE);
        // We only allow empty password from users having a XWikiUsers object.
        if (obj != null) {
          final String stored = obj.getStringValue("password");
          result = new PasswordClass().getEquivalentPassword(stored, password).equals(stored);
        }

        return result;
      } catch (Throwable e) {
        LOGGER.error("Failed to check password", e);
        return false;
      }
    } else {
      throw new XWikiException(
          XWikiException.MODULE_XWIKI_ACCESS,
          XWikiException.ERROR_XWIKI_ACCESS_DENIED,
          "You cannot use this method for checking another user password.",
          null);
    }
  }
  /**
   * Convert the old WorkspaceManager.WorkspaceClass objects to the new configuration format.
   *
   * @param oldObject old workspace object
   * @param wikiId id of the wiki to upgrade
   * @param oldWikiDescriptor document that holds the old object
   * @throws DataMigrationException if problems occur
   * @throws XWikiException if problems occur
   */
  private void upgradeWorkspaceConfiguration(
      BaseObject oldObject, String wikiId, XWikiDocument oldWikiDescriptor)
      throws DataMigrationException, XWikiException {
    // Context, XWiki
    XWikiContext context = getXWikiContext();
    XWiki xwiki = context.getWiki();

    // Create the new configuration
    WikiUserConfiguration configuration = new WikiUserConfiguration();

    // No local users
    configuration.setUserScope(UserScope.GLOBAL_ONLY);

    // Set the membershipType value
    if (oldObject != null) {
      // Get the membershipType value
      String membershipTypeValue = oldObject.getStringValue("membershipType");
      MembershipType membershipType;
      try {
        membershipType = MembershipType.valueOf(membershipTypeValue.toUpperCase());
      } catch (Exception e) {
        // Default value
        membershipType = MembershipType.INVITE;
      }
      configuration.setMembershipType(membershipType);
    } else {
      // If there is no workspace object, we put a default value.
      configuration.setMembershipType(MembershipType.INVITE);
    }

    // Save the new configuration
    saveConfiguration(configuration, wikiId);
  }
 private void setRights(BaseObject rightsObject, String field, String value) {
   String currentValue = rightsObject.getStringValue(field);
   if (!StringUtils.isEmpty(currentValue)) {
     currentValue += ",";
   }
   rightsObject.setLargeStringValue(field, currentValue + value);
 }
 private Visibility getVisibility(XWikiDocument doc) {
   String visibility = null;
   BaseObject visibilityObj = doc.getXObject(Visibility.CLASS_REFERENCE);
   if (visibilityObj != null) {
     visibility = visibilityObj.getStringValue("visibility");
   }
   return this.manager.resolveVisibility(StringUtils.defaultIfBlank(visibility, "private"));
 }
  /**
   * Adds the document comments using the multiValued field {@link Fields#COMMENT}.
   *
   * @param solrDocument the Solr document where to add the comments.
   * @param originalDocument the XWiki document from which to extract the comments.
   */
  protected void addComments(SolrInputDocument solrDocument, XWikiDocument originalDocument) {
    List<BaseObject> comments = originalDocument.getComments();
    if (comments == null) {
      return;
    }

    for (BaseObject comment : comments) {
      // Yes, objects can be null at this point...
      if (comment != null) {
        String commentString = comment.getStringValue("comment");
        String author = comment.getStringValue("author");
        Date date = comment.getDateValue("date");
        solrDocument.addField(
            Fields.COMMENT, String.format("%s by %s on %s", commentString, author, date));
      }
    }
  }
  @Test
  public void loadBotData() throws Exception {
    BaseObject botDataObject = mock(BaseObject.class);

    when(configDoc.getXObject(WIKI_BOT_CONFIGURATION_CLASS)).thenReturn(botDataObject);
    when(botDataObject.getStringValue("botname")).thenReturn("mybotname");
    when(botDataObject.getStringValue("server")).thenReturn("myserver");
    when(botDataObject.getStringValue("channel")).thenReturn("mychannel");
    when(botDataObject.getStringValue("password")).thenReturn("mypassword");
    when(botDataObject.getIntValue("inactive")).thenReturn(0);

    BotData botData = this.componentManager.getComponentUnderTest().loadBotData();
    Assert.assertEquals("mybotname", botData.getName());
    Assert.assertEquals("myserver", botData.getServer());
    Assert.assertEquals("mychannel", botData.getChannel());
    Assert.assertEquals("mypassword", botData.getPassword());
    Assert.assertTrue(botData.isActive());
  }
 /**
  * Trigger a BaseObject job (execute it now).
  *
  * @param object the BaseObject Job to be triggered
  * @return true on success, false on failure.
  */
 public boolean triggerJob(BaseObject object) {
   try {
     getProtectedPlugin().triggerJob(object, this.context);
     LOGGER.debug("Trigger Job: [{}]", object.getStringValue("jobName"));
     return true;
   } catch (XWikiException e) {
     this.context.put("error", e.getMessage());
     return false;
   }
 }
 private DocumentReference getOwner(XWikiDocument doc) {
   String owner = null;
   BaseObject ownerObj = doc.getXObject(Owner.CLASS_REFERENCE);
   if (ownerObj != null) {
     owner = ownerObj.getStringValue("owner");
   }
   if (StringUtils.isNotBlank(owner)) {
     return this.stringEntityResolver.resolve(owner);
   } else if (doc.getCreatorReference() != null) {
     return doc.getCreatorReference();
   }
   return null;
 }
Example #16
0
 /**
  * API to retrieve the e-mail address of this user. This e-mail address is taken from the user
  * profile. If the user hasn't changed his profile, then this is the e-mail address he filled in
  * the registration form.
  *
  * @return The e-mail address from the user profile, or <tt>null</tt> if there is an error
  *     retrieving the email.
  * @since 1.1.3
  * @since 1.2.2
  * @since 1.3M2
  */
 public String getEmail() {
   XWikiDocument userDoc;
   try {
     userDoc = getXWikiContext().getWiki().getDocument(this.user.getUser(), getXWikiContext());
     BaseObject obj = userDoc.getObject("XWiki.XWikiUsers");
     return obj.getStringValue("email");
   } catch (Exception e) {
     // APIs should never throw errors, as velocity cannot catch them, and scripts should be
     // as robust as possible. Instead, the code using this should know that null means there
     // was an error, if it really needs to report these exceptions.
     return null;
   }
 }
  /**
   * {@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");
    }
  }
  private void setBundles(String bundles) throws XWikiException {
    XWikiDocument preferencesDocument =
        this.oldcore
            .getMockXWiki()
            .getDocument(this.preferencesDocumentReference, this.oldcore.getXWikiContext());
    BaseObject preferencesObject = preferencesDocument.getXObject();

    if (!bundles.equals(preferencesObject.getStringValue("documentBundles"))) {
      preferencesObject.setStringValue("documentBundles", bundles);

      this.oldcore
          .getMockXWiki()
          .saveDocument(preferencesDocument, "", this.oldcore.getXWikiContext());
    }
  }
 /**
  * Finds all existing rights objects.
  *
  * @param doc XWikiDocument
  * @return map of rights combination as keys, and corresponding existing rights objects as values
  */
 private Map<String, BaseObject> findRights(XWikiDocument doc) {
   List<BaseObject> allRights = doc.getXObjects(RIGHTS_CLASS);
   if (allRights == null) {
     return new HashMap<String, BaseObject>();
   }
   Map<String, BaseObject> rightsObjects = new HashMap<String, BaseObject>();
   List<String> missingRights = new LinkedList<String>(rightsCombinations);
   for (BaseObject right : allRights) {
     // getXObjects returns an ArrayList that could be lacking elements
     if (right == null) {
       continue;
     }
     String rightLevel = right.getStringValue("levels");
     if (rightsCombinations.contains(rightLevel)) {
       rightsObjects.put(rightLevel, right);
     }
   }
   return rightsObjects;
 }
  @Test
  public void getMembersWhenGroupWithOneBlankUser() throws Exception {
    setUpBaseMocks();
    DocumentReference groupReference = new DocumentReference("groupwiki", "XWiki", "grouppage");
    XWikiDocument document = mock(XWikiDocument.class);
    when(document.isNew()).thenReturn(false);
    when(document.getDocumentReference()).thenReturn(groupReference);
    when(xwiki.getDocument(groupReference, this.xwikiContext)).thenReturn(document);
    List<BaseObject> memberObjects = new ArrayList<>();
    BaseObject bo = mock(BaseObject.class);
    when(bo.getStringValue("member")).thenReturn("");
    memberObjects.add(bo);
    when(document.getXObjects(new DocumentReference("groupwiki", "XWiki", "XWikiGroups")))
        .thenReturn(memberObjects);

    Iterator<DocumentReference> iterator =
        new ReferenceUserIterator(groupReference, this.resolver, this.execution);

    assertFalse(iterator.hasNext());
  }
 /**
  * {@inheritDoc} <br>
  * This implementation retrieves all the objects of the annotation class in the document where
  * target points to, and which have the target set to {@code target}.
  *
  * @see org.xwiki.annotation.io.IOService#getAnnotations(String)
  */
 @Override
 public Collection<Annotation> getAnnotations(String target) throws IOServiceException {
   try {
     // parse the target and extract the local reference serialized from it, by the same rules
     EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT);
     // build the target identifier for the annotation
     String localTargetId = target;
     // and the name of the document where it should be stored
     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);
     // and the annotation class objects in it
     List<BaseObject> objects = document.getXObjects(configuration.getAnnotationClassReference());
     // and build a list of Annotation objects
     List<Annotation> result = new ArrayList<Annotation>();
     if (objects == null) {
       return Collections.<Annotation>emptySet();
     }
     for (BaseObject object : objects) {
       // if it's not on the required target, ignore it
       if (object == null
           || !localTargetId.equals(object.getStringValue(Annotation.TARGET_FIELD))) {
         continue;
       }
       // use the object number as annotation id
       result.add(loadAnnotationFromObject(object, deprecatedContext));
     }
     return result;
   } catch (XWikiException e) {
     throw new IOServiceException("An exception has occurred while loading the annotations", e);
   }
 }
 @Override
 public Annotation getAnnotation(String target, String annotationID) throws IOServiceException {
   try {
     if (annotationID == null || target == null) {
       return null;
     }
     // parse the target and extract the local reference serialized from it, by the same rules
     EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT);
     // build the target identifier for the annotation
     String localTargetId = target;
     // and the name of the document where it should be stored
     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);
     // and the annotation class objects in it
     // parse the annotation id as object index
     BaseObject object =
         document.getXObject(
             configuration.getAnnotationClassReference(),
             Integer.valueOf(annotationID.toString()));
     if (object == null || !localTargetId.equals(object.getStringValue(Annotation.TARGET_FIELD))) {
       return null;
     }
     // use the object number as annotation id
     return loadAnnotationFromObject(object, deprecatedContext);
   } catch (NumberFormatException e) {
     throw new IOServiceException("Could not parse annotation id " + annotationID, e);
   } catch (XWikiException e) {
     throw new IOServiceException(
         "An exception has occurred while loading the annotation with id " + annotationID, e);
   }
 }
  private void setUpGroupPageMocks(DocumentReference... references) throws Exception {
    XWikiDocument document = mock(XWikiDocument.class);
    when(document.isNew()).thenReturn(false);
    when(document.getDocumentReference()).thenReturn(references[0]);
    when(xwiki.getDocument(references[0], this.xwikiContext)).thenReturn(document);

    List<BaseObject> memberObjects = new ArrayList<>();
    for (int i = 1; i < references.length; i++) {
      BaseObject bo = mock(BaseObject.class);
      when(bo.getStringValue("member"))
          .thenReturn(references[i].getLastSpaceReference().getName() + references[i].getName());
      memberObjects.add(bo);
    }
    when(document.getXObjects(new DocumentReference("groupwiki", "XWiki", "XWikiGroups")))
        .thenReturn(memberObjects);

    for (int i = 1; i < references.length; i++) {
      setUpUserPageMocks(references[i]);
      when(this.resolver.resolve(
              references[i].getLastSpaceReference().getName() + references[i].getName(),
              references[0]))
          .thenReturn(references[i]);
    }
  }
 boolean validationAllowed(XWikiContext context) {
   String requestHost = context.getRequest().getHttpServletRequest().getRemoteHost();
   if ((requestHost != null) && (requestHost.trim().length() > 0)) {
     BaseObject config =
         context
             .getDoc()
             .getObject("Classes.RemoteUserValidationClass", "host", requestHost, false);
     if (config != null) {
       String serverSecret = config.getStringValue("secret");
       String requestSecret = context.getRequest().get("secret");
       if ((serverSecret != null)
           && (serverSecret.trim().length() > 0)
           && serverSecret.trim().equals(requestSecret.trim())) {
         mLogger.debug(
             "ALLOWING validation for host " + requestHost + " with secret " + requestSecret);
         return true;
       } else {
         mLogger.warn(
             "DENYING validation: Server secret '"
                 + requestSecret
                 + "' does "
                 + "not match expectation!");
       }
     } else {
       mLogger.warn(
           "DENYING validation: No configuration object found for host '" + requestHost + "'.");
     }
   } else {
     mLogger.warn("DENYING validation: Received no requester host!");
   }
   if (context.getUser().startsWith("xwiki:")) {
     mLogger.warn("ALLOWING validation for SUPERADMIN.");
     return true;
   }
   return false;
 }
  @Test
  public void getPlainUserName() throws XWikiException {
    XWikiDocument document = mock(XWikiDocument.class);
    DocumentReference userReference = new DocumentReference("wiki", "XWiki", "user");
    when(document.getDocumentReference()).thenReturn(userReference);
    when(this.storeMock.loadXWikiDoc(any(XWikiDocument.class), any(XWikiContext.class)))
        .thenReturn(document);
    BaseObject userObject = mock(BaseObject.class);
    when(document.getObject("XWiki.XWikiUsers")).thenReturn(userObject);

    when(userObject.getStringValue("first_name")).thenReturn("first<name");
    when(userObject.getStringValue("last_name")).thenReturn("last'name");
    assertEquals("first<name last'name", xwiki.getPlainUserName(userReference, context));

    when(userObject.getStringValue("first_name")).thenReturn("first<name");
    when(userObject.getStringValue("last_name")).thenReturn("");
    assertEquals("first<name", xwiki.getPlainUserName(userReference, context));

    when(userObject.getStringValue("first_name")).thenReturn("");
    when(userObject.getStringValue("last_name")).thenReturn("last'name");
    assertEquals("last'name", xwiki.getPlainUserName(userReference, context));
  }
  @Test
  public void testImportUsersAndGroupsPreserveVersion()
      throws WikiStreamException, XWikiException, ParseException {
    UserInstanceOutputProperties outputProperties = new UserInstanceOutputProperties();

    outputProperties.setPreserveVersion(true);

    importFromXML("user1", outputProperties);

    // XWiki.user1

    XWikiDocument userDocument =
        this.oldcore
            .getMockXWiki()
            .getDocument(
                new DocumentReference("wiki1", "XWiki", "user1"), this.oldcore.getXWikiContext());

    Assert.assertFalse(userDocument.isNew());

    Assert.assertEquals(
        new DocumentReference("wiki1", "XWiki", "user1"), userDocument.getCreatorReference());
    Assert.assertEquals(toDate("2000-01-10 00:00:00.0 UTC"), userDocument.getCreationDate());
    Assert.assertEquals(
        new DocumentReference("wiki1", "XWiki", "user1"), userDocument.getAuthorReference());
    Assert.assertEquals(toDate("2000-01-11 00:00:00.0 UTC"), userDocument.getDate());
    Assert.assertEquals(toDate("2000-01-11 00:00:00.0 UTC"), userDocument.getContentUpdateDate());
    Assert.assertEquals(
        new DocumentReference("wiki1", "XWiki", "user1"), userDocument.getContentAuthorReference());
    Assert.assertEquals(false, userDocument.isMinorEdit());
    Assert.assertEquals("Import", userDocument.getComment());

    BaseObject userObject = userDocument.getXObject(USER_CLASS);
    Assert.assertEquals(0, userObject.getNumber());
    Assert.assertEquals("user1 first name", userObject.getStringValue("first_name"));
    Assert.assertEquals("user1 last name", userObject.getStringValue("last_name"));
    Assert.assertEquals("*****@*****.**", userObject.getStringValue("email"));
    Assert.assertEquals(1, userObject.getIntValue("active"));

    // XWiki.user2

    userDocument =
        this.oldcore
            .getMockXWiki()
            .getDocument(
                new DocumentReference("wiki1", "XWiki", "user2"), this.oldcore.getXWikiContext());

    Assert.assertFalse(userDocument.isNew());

    Assert.assertEquals(
        new DocumentReference("wiki1", "XWiki", "user2"), userDocument.getCreatorReference());
    Assert.assertEquals(toDate("2000-01-20 00:00:00.0 UTC"), userDocument.getCreationDate());
    Assert.assertEquals(
        new DocumentReference("wiki1", "XWiki", "user2"), userDocument.getAuthorReference());
    Assert.assertEquals(toDate("2000-01-21 00:00:00.0 UTC"), userDocument.getDate());
    Assert.assertEquals(toDate("2000-01-21 00:00:00.0 UTC"), userDocument.getContentUpdateDate());
    Assert.assertEquals(
        new DocumentReference("wiki1", "XWiki", "user2"), userDocument.getContentAuthorReference());
    Assert.assertEquals(false, userDocument.isMinorEdit());
    Assert.assertEquals("Import", userDocument.getComment());

    userObject = userDocument.getXObject(USER_CLASS);
    Assert.assertEquals(0, userObject.getNumber());
    Assert.assertEquals("user2 first name", userObject.getStringValue("first_name"));
    Assert.assertEquals("user2 last name", userObject.getStringValue("last_name"));
    Assert.assertEquals("*****@*****.**", userObject.getStringValue("email"));
    Assert.assertEquals(0, userObject.getIntValue("active"));

    // XWiki.group1

    XWikiDocument groupDocument =
        this.oldcore
            .getMockXWiki()
            .getDocument(
                new DocumentReference("wiki1", "XWiki", "group1"), this.oldcore.getXWikiContext());

    Assert.assertFalse(groupDocument.isNew());

    BaseObject groupMemberObject0 = groupDocument.getXObject(GROUP_CLASS, 0);
    Assert.assertEquals("XWiki.user1", groupMemberObject0.getStringValue("member"));
    BaseObject groupMemberObject1 = groupDocument.getXObject(GROUP_CLASS, 1);
    Assert.assertEquals("XWiki.user2", groupMemberObject1.getStringValue("member"));

    // XWiki.group2

    groupDocument =
        this.oldcore
            .getMockXWiki()
            .getDocument(
                new DocumentReference("wiki1", "XWiki", "group2"), this.oldcore.getXWikiContext());

    Assert.assertFalse(groupDocument.isNew());

    groupMemberObject0 = groupDocument.getXObject(GROUP_CLASS, 0);
    Assert.assertEquals("XWiki.group1", groupMemberObject0.getStringValue("member"));

    // XWiki.emptygroup

    groupDocument =
        this.oldcore
            .getMockXWiki()
            .getDocument(
                new DocumentReference("wiki1", "XWiki", "emptygroup"),
                this.oldcore.getXWikiContext());

    Assert.assertFalse(groupDocument.isNew());

    groupMemberObject0 = groupDocument.getXObject(GROUP_CLASS, 0);
    Assert.assertEquals("", groupMemberObject0.getStringValue("member"));
  }
  /**
   * Creates a {@link WikiMacro} from an {@link XWikiDocument} which contains a macro definition.
   *
   * @param doc the {@link XWikiDocument} to look for a macro definition
   * @return the {@link WikiMacro} found inside the document
   * @throws WikiMacroException when an invalid macro definition or no macro definition was found
   */
  private WikiMacro buildMacro(XWikiDocument doc) throws WikiMacroException {
    DocumentReference documentReference = doc.getDocumentReference();

    // Check whether this document contains a macro definition.
    BaseObject macroDefinition = doc.getObject(WIKI_MACRO_CLASS);
    if (null == macroDefinition) {
      throw new WikiMacroException(
          String.format("No macro definition found in document : [%s]", documentReference));
    }

    // Extract macro definition.
    String macroId = macroDefinition.getStringValue(MACRO_ID_PROPERTY);
    String macroName = macroDefinition.getStringValue(MACRO_NAME_PROPERTY);
    // The macro description as plain text
    String macroDescription = macroDefinition.getStringValue(MACRO_DESCRIPTION_PROPERTY);
    String macroDefaultCategory = macroDefinition.getStringValue(MACRO_DEFAULT_CATEGORY_PROPERTY);
    WikiMacroVisibility macroVisibility =
        WikiMacroVisibility.fromString(macroDefinition.getStringValue(MACRO_VISIBILITY_PROPERTY));
    boolean macroSupportsInlineMode =
        (macroDefinition.getIntValue(MACRO_INLINE_PROPERTY) == 0) ? false : true;
    String macroContentType = macroDefinition.getStringValue(MACRO_CONTENT_TYPE_PROPERTY);
    // The macro content description as plain text
    String macroContentDescription =
        macroDefinition.getStringValue(MACRO_CONTENT_DESCRIPTION_PROPERTY);
    String macroCode = macroDefinition.getStringValue(MACRO_CODE_PROPERTY);

    // Verify macro id.
    if (StringUtils.isEmpty(macroId)) {
      throw new WikiMacroException(
          String.format(
              "Incomplete macro definition in [%s], macro id is empty", documentReference));
    }

    // Verify macro name.
    if (StringUtils.isEmpty(macroName)) {
      macroName = macroId;
      this.logger.debug(
          String.format(
              "Incomplete macro definition in [%s], macro name is empty", documentReference));
    }

    // Verify macro description.
    if (StringUtils.isEmpty(macroDescription)) {
      this.logger.debug(
          String.format(
              "Incomplete macro definition in [%s], macro description is empty",
              documentReference));
    }

    // Verify default macro category.
    if (StringUtils.isEmpty(macroDefaultCategory)) {
      macroDefaultCategory = null;
      this.logger.debug(
          String.format(
              "Incomplete macro definition in [%s], default macro category is empty",
              documentReference));
    }

    // Verify macro content type.
    if (StringUtils.isEmpty(macroContentType)) {
      macroContentType = MACRO_CONTENT_OPTIONAL;
    }

    // Verify macro content description.
    if (!macroContentType.equals(MACRO_CONTENT_EMPTY)
        && StringUtils.isEmpty(macroContentDescription)) {
      String errorMsg = "Incomplete macro definition in [%s], macro content description is empty";
      this.logger.debug(String.format(errorMsg, documentReference));
      macroContentDescription = "Macro content";
    }

    // Verify macro code.
    if (StringUtils.isEmpty(macroCode)) {
      throw new WikiMacroException(
          String.format(
              "Incomplete macro definition in [%s], macro code is empty", documentReference));
    }

    // Extract macro parameters.
    List<WikiMacroParameterDescriptor> parameterDescriptors =
        new ArrayList<WikiMacroParameterDescriptor>();
    Vector<BaseObject> macroParameters = doc.getObjects(WIKI_MACRO_PARAMETER_CLASS);
    if (null != macroParameters) {
      for (BaseObject macroParameter : macroParameters) {
        // Vectors can contain null values
        if (null == macroParameter) {
          continue;
        }

        // Extract parameter definition.
        String parameterName = macroParameter.getStringValue(PARAMETER_NAME_PROPERTY);
        String parameterDescription = macroParameter.getStringValue(PARAMETER_DESCRIPTION_PROPERTY);
        boolean parameterMandatory =
            (macroParameter.getIntValue(PARAMETER_MANDATORY_PROPERTY) == 0) ? false : true;
        String parameterDefaultValue =
            macroParameter.getStringValue(PARAMETER_DEFAULT_VALUE_PROPERTY);

        // Verify parameter name.
        if (StringUtils.isEmpty(parameterName)) {
          throw new WikiMacroException(
              String.format(
                  "Incomplete macro definition in [%s], macro parameter name is empty",
                  documentReference));
        }

        // Verify parameter description.
        if (StringUtils.isEmpty(parameterDescription)) {
          String errorMessage =
              "Incomplete macro definition in [%s], macro parameter description is empty";
          this.logger.debug(String.format(errorMessage, documentReference));
        }

        // If field empty, assume no default value was provided.
        if (StringUtils.isEmpty(parameterDefaultValue)) {
          parameterDefaultValue = null;
        }

        // Create the parameter descriptor.
        parameterDescriptors.add(
            new WikiMacroParameterDescriptor(
                parameterName, parameterDescription, parameterMandatory, parameterDefaultValue));
      }
    }

    // Create macro content descriptor.
    ContentDescriptor contentDescriptor = null;
    if (!macroContentType.equals(MACRO_CONTENT_EMPTY)) {
      contentDescriptor =
          new DefaultContentDescriptor(
              macroContentDescription, macroContentType.equals(MACRO_CONTENT_MANDATORY));
    }

    // Create macro descriptor.
    MacroId id = new MacroId(macroId, doc.getSyntax());
    MacroDescriptor macroDescriptor =
        new WikiMacroDescriptor(
            id,
            macroName,
            macroDescription,
            macroDefaultCategory,
            macroVisibility,
            contentDescriptor,
            parameterDescriptors);

    XDOM xdom;
    try {
      xdom = parser.parse(macroCode, doc.getSyntax(), documentReference);
    } catch (MissingParserException ex) {
      throw new WikiMacroException("Could not find a parser for macro content", ex);
    } catch (ParseException ex) {
      throw new WikiMacroException("Error while parsing macro content", ex);
    }

    // Create & return the macro.
    return new DefaultWikiMacro(
        documentReference,
        doc.getAuthorReference(),
        macroSupportsInlineMode,
        macroDescriptor,
        xdom,
        doc.getSyntax(),
        this.componentManager);
  }
  @Test
  public void getDocumentWithObjects() throws Exception {
    DocumentReference commentsClassReference =
        new DocumentReference("wiki", "space", "commentsClass");
    String commentContent = "This is a comment";
    String commentAuthor = "wiki:space.commentAuthor";
    Date commentDate = new Date();
    // Adding a fake password field to the comments class just to test the branch in the code.
    String commentPassword = "******";
    List<String> commentList = Arrays.asList("a", "list");

    List<BaseProperty<EntityReference>> commentFields =
        new ArrayList<BaseProperty<EntityReference>>();

    // Mock

    BaseProperty<EntityReference> mockCommentField = mock(BaseProperty.class);
    when(mockCommentField.getName()).thenReturn("comment");
    when(mockCommentField.getValue()).thenReturn(commentContent);
    commentFields.add(mockCommentField);

    BaseProperty<EntityReference> mockAuthorField = mock(BaseProperty.class);
    when(mockAuthorField.getName()).thenReturn("author");
    when(mockAuthorField.getValue()).thenReturn(commentAuthor);
    commentFields.add(mockAuthorField);

    BaseProperty<EntityReference> mockDateField = mock(BaseProperty.class);
    when(mockDateField.getName()).thenReturn("date");
    when(mockDateField.getValue()).thenReturn(commentDate);
    commentFields.add(mockDateField);

    BaseProperty<EntityReference> mockPasswordField = mock(BaseProperty.class);
    when(mockPasswordField.getName()).thenReturn("password");
    when(mockPasswordField.getValue()).thenReturn(commentPassword);
    commentFields.add(mockPasswordField);

    BaseProperty<EntityReference> mockListField = mock(BaseProperty.class);
    when(mockListField.getName()).thenReturn("list");
    when(mockListField.getValue()).thenReturn(commentList);
    commentFields.add(mockListField);

    BaseClass mockXClass = mock(BaseClass.class);

    BaseObject mockComment = mock(BaseObject.class);

    // When handled as a comment
    Vector<BaseObject> comments = new Vector<BaseObject>();
    comments.add(mockComment);
    when(mockDocument.getComments()).thenReturn(comments);

    when(mockComment.getStringValue("comment")).thenReturn(commentContent);
    when(mockComment.getStringValue("author")).thenReturn(commentAuthor);
    when(mockComment.getDateValue("date")).thenReturn(commentDate);

    // When handled as a general object
    HashMap<DocumentReference, List<BaseObject>> xObjects =
        new HashMap<DocumentReference, List<BaseObject>>();
    xObjects.put(commentsClassReference, Arrays.asList(mockComment));
    when(mockDocument.getXObjects()).thenReturn(xObjects);

    when(mockComment.getXClass(mockContext)).thenReturn(mockXClass);
    when(mockComment.getFieldList()).thenReturn(commentFields);

    PropertyClass passwordClass = mock(PasswordClass.class);
    when(mockXClass.get("password")).thenReturn(passwordClass);
    when(passwordClass.getClassType()).thenReturn("Password");

    // Call

    DocumentSolrMetadataExtractor extractor =
        (DocumentSolrMetadataExtractor) mocker.getComponentUnderTest();
    SolrInputDocument solrDocument = extractor.getSolrDocument(documentReference);

    // Assert and verify

    Assert.assertEquals(
        String.format("%s by %s on %s", commentContent, commentAuthor, commentDate),
        solrDocument.getFieldValue(
            String.format(Fields.MULTILIGNUAL_FORMAT, Fields.COMMENT, language)));

    Collection<Object> objectProperties =
        solrDocument.getFieldValues(
            String.format(Fields.MULTILIGNUAL_FORMAT, Fields.OBJECT_CONTENT, language));
    MatcherAssert.assertThat(
        objectProperties,
        Matchers.containsInAnyOrder(
            (Object) ("comment:" + commentContent),
            (Object) ("author:" + commentAuthor),
            (Object) ("date:" + commentDate.toString()),
            (Object) ("list:" + commentList.get(0)),
            (Object) ("list:" + commentList.get(1))));
    Assert.assertEquals(5, objectProperties.size());
  }
  /**
   * Convert the old WorkspaceManager.WorkspaceCandidateMemberClass objects to the new candidacies
   * format.
   *
   * @param wikiId id of the wiki to upgrade
   * @throws XWikiException if problems occur
   */
  private void upgradeWorkspaceCandidacies(String wikiId) throws XWikiException {
    XWikiContext xcontext = getXWikiContext();
    XWiki xwiki = xcontext.getWiki();

    // We need to get the document that holds the candidacies
    DocumentReference candidaciesDocumentReference =
        new DocumentReference(wikiId, XWiki.SYSTEM_SPACE, "XWikiAllGroup");
    XWikiDocument candidaciesDocument = xwiki.getDocument(candidaciesDocumentReference, xcontext);

    // We need to get all the old candidacies
    DocumentReference oldCandidateClassReference =
        new DocumentReference(wikiId, XWiki.SYSTEM_SPACE, "WorkspaceCandidateMemberClass");
    List<BaseObject> candidacyObjects = candidaciesDocument.getXObjects(oldCandidateClassReference);
    if (candidacyObjects != null) {
      DocumentReference newCandidateClassReference =
          new DocumentReference(
              wikiId,
              WikiCandidateMemberClassInitializer.DOCUMENT_SPACE,
              WikiCandidateMemberClassInitializer.DOCUMENT_NAME);

      for (BaseObject oldObject : candidacyObjects) {
        if (oldObject == null) {
          continue;
        }
        // Transform the candidacy to the new class
        BaseObject newObject = candidaciesDocument.newXObject(newCandidateClassReference, xcontext);
        newObject.setStringValue(
            WikiCandidateMemberClassInitializer.FIELD_TYPE, oldObject.getStringValue("type"));
        newObject.setStringValue(
            WikiCandidateMemberClassInitializer.FIELD_STATUS, oldObject.getStringValue("status"));
        newObject.setStringValue(
            WikiCandidateMemberClassInitializer.FIELD_USER, oldObject.getStringValue("userName"));
        newObject.setLargeStringValue(
            WikiCandidateMemberClassInitializer.FIELD_USER_COMMENT,
            oldObject.getLargeStringValue("userComment"));
        newObject.setStringValue(
            WikiCandidateMemberClassInitializer.FIELD_ADMIN, oldObject.getStringValue("reviewer"));
        newObject.setLargeStringValue(
            WikiCandidateMemberClassInitializer.FIELD_ADMIN_COMMENT,
            oldObject.getLargeStringValue("reviewerComment"));
        newObject.setLargeStringValue(
            WikiCandidateMemberClassInitializer.FIELD_ADMIN_PRIVATE_COMMENT,
            oldObject.getLargeStringValue("reviewerPrivateComment"));
        newObject.setDateValue(
            WikiCandidateMemberClassInitializer.FIELD_DATE_OF_CREATION,
            oldObject.getDateValue("date"));
        newObject.setDateValue(
            WikiCandidateMemberClassInitializer.FIELD_DATE_OF_CLOSURE,
            oldObject.getDateValue("resolutionDate"));

        // Remove the old object
        candidaciesDocument.removeXObject(oldObject);
      }

      // Save
      xwiki.saveDocument(
          candidaciesDocument,
          "Upgrade candidacies from the old Workspace Application to the "
              + "new Wiki Application.",
          xcontext);
    }
  }