/*
* 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 org.xwiki.wysiwyg.server.internal.wiki;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.xwiki.bridge.DocumentAccessBridge;
import org.xwiki.component.annotation.Component;
import org.xwiki.gwt.wysiwyg.client.wiki.EntityConfig;
import org.xwiki.gwt.wysiwyg.client.wiki.URIReference;
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.EntityReferenceResolver;
import org.xwiki.model.reference.EntityReferenceSerializer;
import org.xwiki.rendering.listener.reference.ResourceReference;
import org.xwiki.rendering.listener.reference.ResourceType;
import org.xwiki.rendering.parser.ResourceReferenceParser;
import org.xwiki.rendering.renderer.reference.ResourceReferenceSerializer;
import org.xwiki.wysiwyg.server.wiki.EntityReferenceConverter;
import org.xwiki.wysiwyg.server.wiki.LinkService;
/**
* The service used to create links.
*
* @version $Id: 0d3ba8fda06728b1a248a82e90e854499c1ee0ca $
*/
@Component
@Singleton
public class DefaultLinkService implements LinkService
{
/**
* The component used to access documents. This is temporary till XWiki model is moved into components.
*/
@Inject
private DocumentAccessBridge documentAccessBridge;
/**
* The component used to serialize XWiki document references.
*/
@Inject
@Named("compact")
private EntityReferenceSerializer<String> entityReferenceSerializer;
/**
* The component used to resolve an entity reference relative to another entity reference.
*/
@Inject
@Named("explicit")
private EntityReferenceResolver<EntityReference> explicitReferenceEntityReferenceResolver;
/**
* The component used to serialize link references.
* <p>
* Note: The link reference syntax is independent of the syntax of the edited document. The current hint should be
* replaced with a generic one to avoid confusion.
*/
@Inject
@Named("xhtmlmarker")
private ResourceReferenceSerializer linkReferenceSerializer;
/**
* The component used to parser link references.
* <p>
* Note: The link reference syntax is independent of the syntax of the edited document. The current hint should be
* replaced with a generic one to avoid confusion.
*/
@Inject
@Named("xhtmlmarker")
private ResourceReferenceParser linkReferenceParser;
/**
* The object used to convert between client and server entity reference.
*/
@Inject
private EntityReferenceConverter entityReferenceConverter;
/**
* Used to resolve a DocumentReference from a SpaceReference, i.e. the space's homepage.
*/
@Inject
private DocumentReferenceResolver<EntityReference> defaultReferenceDocumentReferenceResolver;
@Inject
private EntityReferenceResolver<ResourceReference> resourceReferenceResolver;
@Override
public EntityConfig getEntityConfig(org.xwiki.gwt.wysiwyg.client.wiki.EntityReference origin,
org.xwiki.gwt.wysiwyg.client.wiki.ResourceReference destination)
{
String url;
String destRelativeStrRef;
if (org.xwiki.gwt.wysiwyg.client.wiki.EntityReference.EntityType.EXTERNAL == destination.getEntityReference()
.getType()) {
url = new URIReference(destination.getEntityReference()).getURI();
destRelativeStrRef = url;
} else {
EntityReference originRef = entityReferenceConverter.convert(origin);
EntityReference destRef = entityReferenceConverter.convert(destination.getEntityReference());
destRef = explicitReferenceEntityReferenceResolver.resolve(destRef, destRef.getType(), originRef);
destRelativeStrRef = entityReferenceSerializer.serialize(destRef, originRef);
url = getEntityURL(destRef);
}
EntityConfig entityConfig = new EntityConfig();
entityConfig.setUrl(url);
entityConfig.setReference(getLinkReference(destination.getType(), destination.isTyped(), destRelativeStrRef));
return entityConfig;
}
/**
* @param entityReference an entity reference
* @return the URL to access the specified entity
*/
private String getEntityURL(EntityReference entityReference)
{
switch (entityReference.getType()) {
case DOCUMENT:
DocumentReference documentReference = new DocumentReference(entityReference);
return documentAccessBridge.getDocumentURL(documentReference, "view", null, null);
case ATTACHMENT:
AttachmentReference attachmentReference = new AttachmentReference(entityReference);
return documentAccessBridge.getAttachmentURL(attachmentReference, false);
default:
return null;
}
}
/**
* @param clientResourceType the type of linked resource
* @param typed {@code true} to include the resource scheme in the link reference serialization, {@code false}
* otherwise
* @param relativeStringEntityReference a relative string entity reference
* @return a link reference that can be used to insert a link to the specified entity
*/
private String getLinkReference(
org.xwiki.gwt.wysiwyg.client.wiki.ResourceReference.ResourceType clientResourceType, boolean typed,
String relativeStringEntityReference)
{
ResourceType resourceType = new ResourceType(clientResourceType.getScheme());
ResourceReference linkReference = new ResourceReference(relativeStringEntityReference, resourceType);
linkReference.setTyped(typed);
return linkReferenceSerializer.serialize(linkReference);
}
@Override
public org.xwiki.gwt.wysiwyg.client.wiki.ResourceReference parseLinkReference(String linkReferenceAsString,
org.xwiki.gwt.wysiwyg.client.wiki.EntityReference baseReference)
{
ResourceReference linkReference = linkReferenceParser.parse(linkReferenceAsString);
ResourceType linkResourceType = linkReference.getType();
if (ResourceType.SPACE.equals(linkResourceType)) {
// Treat space resources the same as documents in order to reuse the UI.
linkResourceType = ResourceType.DOCUMENT;
}
org.xwiki.gwt.wysiwyg.client.wiki.ResourceReference clientLinkReference =
new org.xwiki.gwt.wysiwyg.client.wiki.ResourceReference();
clientLinkReference.setType(org.xwiki.gwt.wysiwyg.client.wiki.ResourceReference.ResourceType
.forScheme(linkResourceType.getScheme()));
clientLinkReference.setTyped(linkReference.isTyped());
clientLinkReference.getParameters().putAll(linkReference.getParameters());
clientLinkReference.setEntityReference(parseEntityReferenceFromResourceReference(linkReference,
clientLinkReference.getType(), baseReference));
return clientLinkReference;
}
/**
* Parses a client entity reference from a link/resource reference.
*
* @param resourceReference the resource reference to parse
* @param clientResourceType the previously resolved client-side type of the passed resource reference
* @param baseReference the client entity reference that is used to resolve the parsed entity reference relative to
* @return an untyped client entity reference
*/
private org.xwiki.gwt.wysiwyg.client.wiki.EntityReference parseEntityReferenceFromResourceReference(
ResourceReference resourceReference,
org.xwiki.gwt.wysiwyg.client.wiki.ResourceReference.ResourceType clientResourceType,
org.xwiki.gwt.wysiwyg.client.wiki.EntityReference baseReference)
{
org.xwiki.gwt.wysiwyg.client.wiki.EntityReference result = null;
org.xwiki.gwt.wysiwyg.client.wiki.EntityReference.EntityType clientEntityType;
switch (clientResourceType) {
case DOCUMENT:
clientEntityType = org.xwiki.gwt.wysiwyg.client.wiki.EntityReference.EntityType.DOCUMENT;
break;
case ATTACHMENT:
clientEntityType = org.xwiki.gwt.wysiwyg.client.wiki.EntityReference.EntityType.ATTACHMENT;
break;
default:
clientEntityType = org.xwiki.gwt.wysiwyg.client.wiki.EntityReference.EntityType.EXTERNAL;
break;
}
if (clientEntityType == org.xwiki.gwt.wysiwyg.client.wiki.EntityReference.EntityType.EXTERNAL) {
result = new URIReference(resourceReference.getReference()).getEntityReference();
} else {
EntityReference serverEntityReference =
parseServerEntityReferenceFromResourceReference(resourceReference, baseReference);
result = entityReferenceConverter.convert(serverEntityReference);
}
return result;
}
/**
* @param resourceReference the reference to resolve
* @param baseReference the base reference to use when resolving
* @return the resolved {@link EntityReference}
*/
private EntityReference parseServerEntityReferenceFromResourceReference(ResourceReference resourceReference,
org.xwiki.gwt.wysiwyg.client.wiki.EntityReference baseReference)
{
EntityReference result = null;
EntityReference baseServerEntityReference = entityReferenceConverter.convert(baseReference);
result = resourceReferenceResolver.resolve(resourceReference, null, baseServerEntityReference);
ResourceType resourceType = resourceReference.getType();
// Depending on the resource type, additional work might be needed to resolve the reference.
if (ResourceType.SPACE.equals(resourceType)) {
// Make sure to return the space's WebHome since space links are mapped to documents for now.
result = defaultReferenceDocumentReferenceResolver.resolve(result);
}
return result;
}
}