/*
* 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.internal.skin;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.xwiki.component.annotation.Component;
import org.xwiki.model.reference.AttachmentReference;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.DocumentReferenceResolver;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.model.reference.EntityReferenceSerializer;
import org.xwiki.model.reference.LocalDocumentReference;
import org.xwiki.model.reference.ObjectPropertyReference;
import org.xwiki.skin.Resource;
import org.xwiki.skin.Skin;
import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiAttachment;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.internal.mandatory.XWikiSkinFileOverrideClassDocumentInitializer;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.BaseProperty;
/**
* @version $Id: b4cc7a7112f32791020de9717704dd4df6b02db2 $
* @since 6.4M1
*/
@Component(roles = WikiSkinUtils.class)
@Singleton
public class WikiSkinUtils
{
public static final LocalDocumentReference SKINCLASS_REFERENCE = new LocalDocumentReference("XWiki", "XWikiSkins");
public static final String SKINCLASS_BASESKIN = "baseskin";
/**
* Represents no value (ie the default value will be used) in xproperties.
*/
// TODO: remove when XWIKI-10853 is fixed
private static final String NO_VALUE = "---";
@Inject
private Provider<XWikiContext> xcontextProvider;
@Inject
@Named("currentmixed")
private DocumentReferenceResolver<String> currentMixedDocumentReferenceResolver;
@Inject
private EntityReferenceSerializer<String> referenceSerializer;
@Inject
private Logger logger;
public XWikiDocument getSkinDocument(String skin)
{
XWikiContext xcontext = this.xcontextProvider.get();
if (xcontext != null) {
DocumentReference skinReference = this.currentMixedDocumentReferenceResolver.resolve(skin);
XWiki xwiki = xcontext.getWiki();
if (xwiki != null && xwiki.getStore() != null) {
XWikiDocument doc;
try {
doc = xwiki.getDocument(skinReference, xcontext);
} catch (XWikiException e) {
this.logger.error("Faied to get document [{}]", skinReference, e);
return null;
}
if (!doc.isNew()) {
return doc;
}
}
}
return null;
}
private BaseObject getSkinObject(String skin)
{
XWikiDocument skinDocument = getSkinDocument(skin);
return skinDocument != null ? skinDocument.getXObject(SKINCLASS_REFERENCE) : null;
}
public boolean isWikiSkin(String id)
{
return getSkinDocument(id) != null;
}
public Resource<?> getResource(String resourceName, Skin skin)
{
Resource<?> source = null;
XWikiDocument skinDocument = getSkinDocument(skin.getId());
if (skinDocument != null) {
source = getSkinResourceFromDocumentSkin(resourceName, skinDocument, skin);
}
return source;
}
private Resource<?> getSkinResourceFromDocumentSkin(String resource, XWikiDocument skinDocument, Skin skin)
{
if (skinDocument != null) {
// Try to find a XWikiSkinFileOverrideClass object
BaseObject obj = skinDocument.getXObject(XWikiSkinFileOverrideClassDocumentInitializer.DOCUMENT_REFERENCE,
XWikiSkinFileOverrideClassDocumentInitializer.PROPERTY_PATH, resource, false);
if (obj != null) {
ObjectPropertyReference reference = new ObjectPropertyReference(
XWikiSkinFileOverrideClassDocumentInitializer.PROPERTY_CONTENT,
obj.getReference());
return new ObjectPropertyWikiResource(getPath(reference), skin, reference,
skinDocument.getAuthorReference(), this.xcontextProvider,
obj.getLargeStringValue(XWikiSkinFileOverrideClassDocumentInitializer.PROPERTY_CONTENT));
}
// Try parsing the object property
BaseProperty<ObjectPropertyReference> property = getSkinResourceProperty(resource, skinDocument);
if (property != null) {
ObjectPropertyReference reference = property.getReference();
return new ObjectPropertyWikiResource(getPath(reference), skin, reference,
skinDocument.getAuthorReference(), this.xcontextProvider, (String) property.getValue());
}
// Try parsing a document attachment
// Convert "/" into "." in order to support wiki skin attachments to override some resources located in
// subdirectories.
String normalizedResourceName = StringUtils.replaceChars(resource, '/', '.');
XWikiAttachment attachment = skinDocument.getAttachment(normalizedResourceName);
if (attachment != null) {
AttachmentReference reference = attachment.getReference();
return new AttachmentWikiResource(getPath(reference), skin, reference, attachment.getAuthorReference(),
this.xcontextProvider);
}
}
return null;
}
private BaseProperty<ObjectPropertyReference> getSkinResourceProperty(String resource, XWikiDocument skinDocument)
{
// Try parsing the object property
BaseObject skinObject = skinDocument.getXObject(SKINCLASS_REFERENCE);
if (skinObject != null) {
BaseProperty<ObjectPropertyReference> resourceProperty =
(BaseProperty<ObjectPropertyReference>) skinObject.safeget(resource);
// If not found try by replacing '/' with '.'
if (resourceProperty == null) {
String escapedTemplateName = StringUtils.replaceChars(resource, '/', '.');
resourceProperty = (BaseProperty<ObjectPropertyReference>) skinObject.safeget(escapedTemplateName);
}
if (resourceProperty != null) {
Object value = resourceProperty.getValue();
if (value instanceof String && StringUtils.isNotEmpty((String) value)) {
return resourceProperty;
}
}
}
return null;
}
public String getSkinProperty(String skin, String property)
{
BaseObject obj = getSkinObject(skin);
if (obj != null) {
return obj.getStringValue(property);
}
return null;
}
public String getParentId(String id)
{
BaseObject skinObject = getSkinObject(id);
if (skinObject != null) {
String parentId = skinObject.getStringValue(SKINCLASS_BASESKIN);
// TODO: remove the NO_VALUE test when XWIKI-10853 is fixed
if (StringUtils.isNotBlank(parentId) && !NO_VALUE.equals(parentId)) {
return parentId;
}
}
return null;
}
private String getPath(EntityReference reference)
{
return this.referenceSerializer.serialize(reference);
}
}