Java tutorial
/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package com.xpn.xwiki; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Hashtable; import java.util.List; import java.util.Map; import org.apache.commons.collections.map.LRUMap; import org.apache.commons.lang3.StringUtils; import org.apache.xmlrpc.server.XmlRpcServer; import org.xwiki.context.Execution; import org.xwiki.model.reference.DocumentReference; import org.xwiki.model.reference.DocumentReferenceResolver; import org.xwiki.model.reference.EntityReferenceSerializer; import org.xwiki.model.reference.SpaceReference; import org.xwiki.model.reference.WikiReference; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.doc.XWikiDocumentArchive; import com.xpn.xwiki.objects.classes.BaseClass; import com.xpn.xwiki.user.api.XWikiRightService; import com.xpn.xwiki.user.api.XWikiUser; import com.xpn.xwiki.util.Util; import com.xpn.xwiki.validation.XWikiValidationStatus; import com.xpn.xwiki.web.Utils; import com.xpn.xwiki.web.XWikiEngineContext; import com.xpn.xwiki.web.XWikiForm; import com.xpn.xwiki.web.XWikiMessageTool; import com.xpn.xwiki.web.XWikiRequest; import com.xpn.xwiki.web.XWikiResponse; import com.xpn.xwiki.web.XWikiURLFactory; public class XWikiContext extends Hashtable<Object, Object> { public static final int MODE_SERVLET = 0; public static final int MODE_PORTLET = 1; public static final int MODE_XMLRPC = 2; public static final int MODE_ATOM = 3; public static final int MODE_PDF = 4; public static final int MODE_GWT = 5; public static final int MODE_GWT_DEBUG = 6; public static final String EXECUTIONCONTEXT_KEY = "xwikicontext"; private static final String WIKI_KEY = "wiki"; private static final String ORIGINAL_WIKI_KEY = "originalWiki"; private static final String USER_KEY = "user"; private static final String USERREFERENCE_KEY = "userreference"; private boolean finished = false; private XWiki wiki; private XWikiEngineContext engine_context; private XWikiRequest request; private XWikiResponse response; private XWikiForm form; private String action; private String orig_database; private String database; private DocumentReference userReference; private String language; private static final String LANGUAGE_KEY = "language"; private String interfaceLanguage; private int mode; private URL url; private XWikiURLFactory URLFactory; private XmlRpcServer xmlRpcServer; private String wikiOwner; private XWikiDocument wikiServer; private int cacheDuration = 0; private int classCacheSize = 20; private int archiveCacheSize = 20; // Used to avoid recursive loading of documents if there are recursives usage of classes @SuppressWarnings("unchecked") private Map<DocumentReference, BaseClass> classCache = Collections .synchronizedMap(new LRUMap(this.classCacheSize)); // Used to avoid reloading archives in the same request @SuppressWarnings("unchecked") private Map<String, XWikiDocumentArchive> archiveCache = Collections .synchronizedMap(new LRUMap(this.archiveCacheSize)); private List<String> displayedFields = Collections.synchronizedList(new ArrayList<String>()); /** * Used to resolve a string into a proper Document Reference using the current document's reference to fill the * blanks, except for the page name for which the default page name is used instead and for the wiki name for which * the current wiki is used instead of the current document reference's wiki. */ @SuppressWarnings("unchecked") private DocumentReferenceResolver<String> currentMixedDocumentReferenceResolver = Utils .getComponent(DocumentReferenceResolver.class, "currentmixed"); /** * Used to convert a proper Document Reference to a string but without the wiki name. */ @SuppressWarnings("unchecked") private EntityReferenceSerializer<String> localEntityReferenceSerializer = Utils .getComponent(EntityReferenceSerializer.class, "local"); /** * Used to convert a Document Reference to string (compact form without the wiki part if it matches the current * wiki). */ @SuppressWarnings("unchecked") private EntityReferenceSerializer<String> compactWikiEntityReferenceSerializer = Utils .getComponent(EntityReferenceSerializer.class, "compactwiki"); /** The Execution so that we can check if permissions were dropped there. */ private final Execution execution = Utils.getComponent(Execution.class); public XWikiContext() { } public XWiki getWiki() { return this.wiki; } public Util getUtil() { Util util = (Util) this.get("util"); if (util == null) { util = new Util(); this.put("util", util); } return util; } public void setWiki(XWiki wiki) { this.wiki = wiki; } public XWikiEngineContext getEngineContext() { return this.engine_context; } public void setEngineContext(XWikiEngineContext engine_context) { this.engine_context = engine_context; } public XWikiRequest getRequest() { return this.request; } public void setRequest(XWikiRequest request) { this.request = request; } public String getAction() { return this.action; } public void setAction(String action) { this.action = action; } public XWikiResponse getResponse() { return this.response; } public void setResponse(XWikiResponse response) { this.response = response; } public String getDatabase() { return this.database; } public void setDatabase(String database) { this.database = database; if (database == null) { super.remove(WIKI_KEY); } else { super.put(WIKI_KEY, database); } if (this.orig_database == null) { this.orig_database = database; if (database == null) { super.remove(ORIGINAL_WIKI_KEY); } else { super.put(ORIGINAL_WIKI_KEY, database); } } } /** * {@inheritDoc} * <p> * Make sure to keep {@link #database} fields and map synchronized. * * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object) */ @Override public synchronized Object put(Object key, Object value) { Object previous; if (WIKI_KEY.equals(key)) { previous = get(WIKI_KEY); setDatabase((String) value); } else { previous = super.put(key, value); } return previous; } /** * {@inheritDoc} * <p> * Make sure to keep {@link #database} field and map synchronized. * * @see java.util.Hashtable#remove(java.lang.Object) */ @Override public synchronized Object remove(Object key) { Object previous; if (WIKI_KEY.equals(key)) { previous = get(WIKI_KEY); setDatabase(null); } else { previous = super.remove(key); } return previous; } /** * Get the "original" database name. In single wiki mode this will be "xwiki", but in virtual wiki mode this will be * the database name for the wiki which the user requested. If the database is switched to load some piece of data, * this will remember what it should be switched back to. * * @return the db name originally requested by the user. */ public String getOriginalDatabase() { return this.orig_database; } public void setOriginalDatabase(String database) { this.orig_database = database; if (database == null) { remove(ORIGINAL_WIKI_KEY); } else { put(ORIGINAL_WIKI_KEY, database); } } /** * @return true it's main wiki's context, false otherwise. */ public boolean isMainWiki() { return isMainWiki(getDatabase()); } /** * @param wikiName the name of the wiki. * @return true it's main wiki's context, false otherwise. */ public boolean isMainWiki(String wikiName) { return (getWiki() != null && !getWiki().isVirtualMode()) || StringUtils.equalsIgnoreCase(wikiName, getMainXWiki()); } public XWikiDocument getDoc() { return (XWikiDocument) get("doc"); } public void setDoc(XWikiDocument doc) { if (doc == null) { remove("doc"); } else { put("doc", doc); } } public DocumentReference getUserReference() { return this.userReference; } public void setUserReference(DocumentReference userReference) { if (userReference == null) { this.userReference = null; remove(USER_KEY); remove(USERREFERENCE_KEY); } else { this.userReference = new DocumentReference(userReference); boolean ismain = isMainWiki(this.userReference.getWikiReference().getName()); put(USER_KEY, new XWikiUser(getUser(), ismain)); put(USERREFERENCE_KEY, this.userReference); } } /** * @deprecated since 3.1M1 use {@link #setUserReference(DocumentReference)} instead */ @Deprecated public void setUser(String user, boolean main) { if (user == null) { setUserReference(null); } else if (user.endsWith(XWikiRightService.GUEST_USER_FULLNAME) || user.equals(XWikiRightService.GUEST_USER)) { setUserReference(null); // retro-compatibilty hack: some code does not give the same meaning to null XWikiUser and XWikiUser // containing guest user put(USER_KEY, new XWikiUser(user, main)); } else { setUserReference(resolveUserReference(user)); } } /** * Make sure to use "XWiki" as default space when it's not provided in user name. */ private DocumentReference resolveUserReference(String user) { return this.currentMixedDocumentReferenceResolver.resolve(user, new SpaceReference("XWiki", new WikiReference(getDatabase() == null ? "xwiki" : getDatabase()))); } /** * @deprecated since 3.1M1 use {@link #setUserReference(DocumentReference)} instead */ @Deprecated public void setUser(String user) { setUser(user, false); } /** * @deprecated since 3.1M1 use {@link #getUserReference()} instead */ @Deprecated public String getUser() { if (this.userReference != null) { if (getDatabase() == null) { return this.localEntityReferenceSerializer.serialize(this.userReference); } else { return this.compactWikiEntityReferenceSerializer.serialize(this.userReference, new WikiReference(getDatabase())); } } else { return XWikiRightService.GUEST_USER_FULLNAME; } } /** * @deprecated since 3.1M1 use {@link #getUserReference()} instead */ @Deprecated public String getLocalUser() { if (this.userReference != null) { return this.localEntityReferenceSerializer.serialize(this.userReference); } else { return XWikiRightService.GUEST_USER_FULLNAME; } } /** * @deprecated since 3.1M1 use {@link #getUserReference()} instead */ @Deprecated public XWikiUser getXWikiUser() { if (this.userReference != null) { boolean ismain = isMainWiki(this.userReference.getWikiReference().getName()); return new XWikiUser(getUser(), ismain); } return (XWikiUser) get(USER_KEY); } public String getLanguage() { return this.language; } public void setLanguage(String language) { this.language = Util.normalizeLanguage(language); if (language == null) { remove(LANGUAGE_KEY); } else { put(LANGUAGE_KEY, language); } } public String getInterfaceLanguage() { return this.interfaceLanguage; } public void setInterfaceLanguage(String interfaceLanguage) { this.interfaceLanguage = interfaceLanguage; } public int getMode() { return this.mode; } public void setMode(int mode) { this.mode = mode; } public URL getURL() { return this.url; } public void setURL(URL url) { this.url = url; } public XWikiURLFactory getURLFactory() { return this.URLFactory; } public void setURLFactory(XWikiURLFactory URLFactory) { this.URLFactory = URLFactory; } public XWikiForm getForm() { return this.form; } public void setForm(XWikiForm form) { this.form = form; } public boolean isFinished() { return this.finished; } public void setFinished(boolean finished) { this.finished = finished; } public XmlRpcServer getXMLRPCServer() { return this.xmlRpcServer; } public void setXMLRPCServer(XmlRpcServer xmlRpcServer) { this.xmlRpcServer = xmlRpcServer; } public void setWikiOwner(String wikiOwner) { this.wikiOwner = wikiOwner; } public String getWikiOwner() { return this.wikiOwner; } public void setWikiServer(XWikiDocument doc) { this.wikiServer = doc; } public XWikiDocument getWikiServer() { return this.wikiServer; } public int getCacheDuration() { return this.cacheDuration; } public void setCacheDuration(int cacheDuration) { this.cacheDuration = cacheDuration; } public String getMainXWiki() { return (String) get("mainxwiki"); } public void setMainXWiki(String str) { put("mainxwiki", str); } // Used to avoid recursive loading of documents if there are recursives usage of classes public void addBaseClass(BaseClass bclass) { this.classCache.put(bclass.getDocumentReference(), bclass); } /** * @since 2.2M2 */ // Used to avoid recursive loading of documents if there are recursives usage of classes public BaseClass getBaseClass(DocumentReference documentReference) { return this.classCache.get(documentReference); } /** * @deprecated since 2.2M2 use {@link #getBaseClass(DocumentReference)} */ // Used to avoid recursive loading of documents if there are recursives usage of classes @Deprecated public BaseClass getBaseClass(String name) { BaseClass baseClass = null; if (StringUtils.isNotEmpty(name)) { baseClass = this.classCache.get(this.currentMixedDocumentReferenceResolver.resolve(name)); } return baseClass; } /** * Empty the class cache. */ public void flushClassCache() { this.classCache.clear(); } // Used to avoid recursive loading of documents if there are recursives usage of classes public void addDocumentArchive(String key, XWikiDocumentArchive obj) { this.archiveCache.put(key, obj); } // Used to avoid recursive loading of documents if there are recursives usage of classes public XWikiDocumentArchive getDocumentArchive(String key) { return this.archiveCache.get(key); } /** * Empty the archive cache. */ public void flushArchiveCache() { this.archiveCache.clear(); } public void setLinksAction(String action) { put("links_action", action); } public void unsetLinksAction() { remove("links_action"); } public String getLinksAction() { return (String) get("links_action"); } public void setLinksQueryString(String value) { put("links_qs", value); } public void unsetLinksQueryString() { remove("links_qs"); } public String getLinksQueryString() { return (String) get("links_qs"); } public XWikiMessageTool getMessageTool() { XWikiMessageTool msg = ((XWikiMessageTool) get("msg")); if (msg == null) { getWiki().prepareResources(this); msg = ((XWikiMessageTool) get("msg")); } return msg; } public XWikiValidationStatus getValidationStatus() { return (XWikiValidationStatus) get("validation_status"); } public void setValidationStatus(XWikiValidationStatus status) { put("validation_status", status); } public void addDisplayedField(String fieldname) { this.displayedFields.add(fieldname); } public List<String> getDisplayedFields() { return this.displayedFields; } public String getEditorWysiwyg() { return (String) get("editor_wysiwyg"); } /** * Drop permissions for the remainder of the request cycle. * After this is called: * <ul> * <li>1. {@link com.xpn.xwiki.api.Api#hasProgrammingRights()} will always return false.</li> * <li>2. {@link com.xpn.xwiki.api.XWiki#getDocumentAsAuthor(org.xwiki.model.reference.DocumentReference)}, * {@link com.xpn.xwiki.api.XWiki#getDocumentAsAuthor(String)}, {@link com.xpn.xwiki.api.Document#saveAsAuthor()}, * {@link com.xpn.xwiki.api.Document#saveAsAuthor(String)}, * {@link com.xpn.xwiki.api.Document#saveAsAuthor(String, boolean)}, and * {@link com.xpn.xwiki.api.Document#deleteAsAuthor()} will perform all of their actions as if the document's * content author was the guest user (XWiki.XWikiGuest).</li> * </ul> * <p> * In effect, no code requiring "programming right" will run, and if the document content author (see: * {@link com.xpn.xwiki.api.Document#getContentAuthor()}) is a user who has "programming right", there will be no * way for code following this call to save another document as this user, blessing it too with programming right. * <p> * Once dropped, permissions cannot be regained for the duration of the request. * * <p> * If you are interested in a more flexable sandboxing method which sandboxed code only * for the remainder of the rendering cycle, consider using * {@link com.xpn.xwiki.api.Document#dropPermissions()}. * <p> * * @since 3.0M3 */ public void dropPermissions() { this.put(XWikiConstant.DROPPED_PERMISSIONS, Boolean.TRUE); } /** * @return true if {@link XWikiContext#dropPermissions()} has been called * on this context, or if the {@link XWikiConstant.DROPPED_PERMISSIONS} * key has been set in the {@link org.xwiki.context.ExecutionContext} * for this thread. This is done by calling {@Document#dropPermissions()} */ public boolean hasDroppedPermissions() { if (this.get(XWikiConstant.DROPPED_PERMISSIONS) != null) { return true; } final Object dropped = this.execution.getContext().getProperty(XWikiConstant.DROPPED_PERMISSIONS); if (dropped == null || !(dropped instanceof Integer)) { return false; } return ((Integer) dropped) == System.identityHashCode(this.execution.getContext()); } }