public void init(XWikiContext context) throws XWikiException, IOException {
    // first check versions
    XWikiDocument doc = xwiki.getDocument(docFullName, context);
    String xwikiVersion = doc.getVersion();

    String fn = "fullname:" + docFullName;
    String solrRev = useBackEnd ? currikiPlugin.solrGetSingleValue(fn, "revisionNumber") : "";
    if (useBackEnd && xwikiVersion.equals(solrRev)) {
      isBackEndStream = true;
      get = currikiPlugin.solrCreateQueryGetMethod(fn, solrField, 0, 100);
      currikiPlugin.solrCollectResultsFromQuery(
          "fullname:" + docFullName,
          "childRights,childPages",
          0,
          1,
          new CurrikiPlugin.SolrResultCollector() {
            public void status(int statusCode, int qTime, int numFound, int start) {}

            public void newDocument() {}

            public void addValue(String name, String value) {
              if ("childRights".equals(name)) childRightsS = value;
              else if ("childPages".equals(name)) childPagesS = value;
            }
          });
    } else {
      isBackEndStream = false;
      // identify docs to queries
      if (type == Type.USER_COLLECTIONS) {
        propNameForFullname = "collectionPage";
        subAssetNames = currikiPlugin.fetchCollectionsList(docFullName, context);
        objectToOutput = currikiPlugin.fetchCollectionsInfo(docFullName, context);
      } else if (type == Type.GROUP_COLLECTIONS) {
        propNameForFullname = "collectionPage";
        String groupName = docFullName.replace(".WebPreferences", "");
        subAssetNames = currikiPlugin.fetchCollectionsList(groupName, context);
        objectToOutput = currikiPlugin.fetchCollectionsInfo(groupName, context);
      } else if (type == Type.USER_GROUPS) {
        propNameForFullname = "groupSpace";
        subAssetNames = null;
        objectToOutput = currikiPlugin.fetchUserGroups(docFullName, context);
      } else if (type == Type.COLLECTION_CONTENT) {
        propNameForFullname = "assetpage";

        FolderCompositeAsset fca =
            (FolderCompositeAsset)
                currikiPlugin.fetchAssetAs(docFullName, FolderCompositeAsset.class, context);
        if (fca != null) {
          FolderCompositeAsset fAsset = fca.as(FolderCompositeAsset.class);
          objectToOutput = fAsset.getSubassetsInfo();
        } else objectToOutput = new LinkedList();
      } else {
        throw new UnsupportedEncodingException();
      }
    }
  }
  public CTVRepresentation(String targetDocument, Type type, XWikiContext context)
      throws IOException, XWikiException {
    super(jsonMediaType);
    this.xwiki = context.getWiki();
    this.userGroups = new TreeSet<String>();
    for (Object groupName :
        ((CurrikiSpaceManager) xwiki.getPlugin("csm", context))
            .getSpaceNames(context.getUser(), null, context)) {
      userGroups.add(((String) groupName).substring("Group_".length()));
    }
    this.type = type;
    this.userName = context.getUser();
    if (userName.startsWith("XWiki.")) userName = userName.substring("XWiki.".length());
    this.userIsAdmin =
        xwiki.checkAccess("admin", xwiki.getDocument("XWiki.XWikiPreferences", context), context);
    this.docFullName = targetDocument;
    this.currikiPlugin = (CurrikiPlugin) xwiki.getPlugin("curriki", context);

    if (!currikiPlugin.solrCheckIsUp()) useBackEnd = false;

    // identify docs to queries
    if (type == Type.USER_COLLECTIONS) {
      solrField = "userCollections";
      propNameForFullname = "collectionPage";
    } else if (type == Type.USER_GROUPS) {
      solrField = "userGroups";
      propNameForFullname = "groupSpace";
    } else if (type == Type.GROUP_COLLECTIONS) {
      solrField = "childInfo";
      propNameForFullname = "collectionPage";
    } else if (type == Type.COLLECTION_CONTENT) {
      solrField = "childInfo";
      propNameForFullname = "assetpage";
    } else {
      throw new UnsupportedEncodingException();
    }
  }
  public void write(final Writer out) throws IOException {
    try {
      if (isBackEndStream) {
        boolean isSubassetsQuery =
            type == Type.COLLECTION_CONTENT || type == Type.GROUP_COLLECTIONS;
        final StringTokenizer
            childRights = isSubassetsQuery ? new StringTokenizer(childRightsS, ",") : null,
            childPages = isSubassetsQuery ? new StringTokenizer(childPagesS, ",") : null;
        currikiPlugin.startSolrMethod(get);
        if (isSubassetsQuery) {
          out.write("[");
          CurrikiPlugin.SolrResultCollector collector =
              new CurrikiPlugin.SolrResultCollector() {
                boolean started = false;

                public void status(int statusCode, int qTime, int numFound, int start) {}

                public void newDocument() {}

                public void addValue(String name, String value) {
                  if (!value.startsWith("{")) value = value.trim();
                  if (!value.startsWith("{"))
                    throw new IllegalStateException(
                        "Child metadata value \"" + value + "\" incompatible!");
                  String right = childRights != null ? childRights.nextToken() : null;
                  String assetpage = childPages.nextToken();
                  try {
                    if (!started) started = true;
                    else out.write(", "); // \n
                    if (childRights != null && canUserRead(right)) {
                      System.err.println(
                          "Rights: view: "
                              + canUserRead(right)
                              + ", edit:"
                              + canUserModify(right)
                              + ", delete:"
                              + canUserDelete(assetpage)
                              + ".");
                      // TODO: convert the label "rights" to "ownership"
                      if (canUserModify(right))
                        out.write("{rights:{'view':true, 'edit':true, 'delete': ");
                      else out.write("{rights:{'view':true, 'edit':false, 'delete': ");
                      if (canUserDelete(assetpage)) out.write("true},");
                      else out.write("false},");
                      out.write(value.substring(1));
                    } else { // no read allowance
                      out.write(
                          "{rights:{'view':false, 'edit':false, 'delete': false}, assetpage: \""
                              + assetpage
                              + "\",");
                      out.write(ghostSubAssetInfoJson);
                    }
                  } catch (Exception e) {
                    throw new IllegalStateException(e);
                  }
                }
              };
          currikiPlugin.feedFieldFromXmlStream(get, collector, solrField);
          out.write("]");
        } else { // Type.USER_COLLECTIONS, Type.USER_GROUPS: always requested from own user
                 // currently, can be static
          currikiPlugin.feedFieldFromXmlStream(get, out, solrField);
        }
      } else {
        if (objectToOutput instanceof Map) {
          new Gson()
              .toJson(
                  subAssetNames == null
                      ? flattenMapToJSONArray(
                          (Map<String, Object>) objectToOutput, propNameForFullname)
                      : flattenMapToJSONArray(
                          (Map<String, Object>) objectToOutput, subAssetNames, propNameForFullname),
                  out);
        } else {
          new Gson().toJson(objectToOutput, out);
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
      throw new IllegalStateException(e);
    }
  }