You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by aj...@apache.org on 2008/08/03 14:17:35 UTC
svn commit: r682144 [4/4] - in
/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki:
auth/authorize/ auth/login/ auth/permissions/ auth/user/ content/
Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/user/XMLUserDatabase.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/user/XMLUserDatabase.java?rev=682144&r1=682143&r2=682144&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/user/XMLUserDatabase.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/user/XMLUserDatabase.java Sun Aug 3 05:17:34 2008
@@ -1,21 +1,22 @@
/*
- JSPWiki - a JSP-based WikiWiki clone.
+ JSPWiki - a JSP-based WikiWiki clone.
- Copyright (C) 2001-2005 Janne Jalkanen (Janne.Jalkanen@iki.fi)
-
- This program 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 program 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 program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
*/
package com.ecyrd.jspwiki.auth.user;
@@ -24,17 +25,12 @@
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Properties;
-import java.util.Set;
+import java.util.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
+import org.w3c.dom.*;
import org.xml.sax.SAXException;
import com.ecyrd.jspwiki.NoRequiredPropertyException;
@@ -42,6 +38,7 @@
import com.ecyrd.jspwiki.auth.NoSuchPrincipalException;
import com.ecyrd.jspwiki.auth.WikiPrincipal;
import com.ecyrd.jspwiki.auth.WikiSecurityException;
+import com.ecyrd.jspwiki.util.Serializer;
/**
* <p>Manages {@link DefaultUserProfile} objects using XML files for persistence.
@@ -73,6 +70,8 @@
private static final String DEFAULT_USERDATABASE = "userdatabase.xml";
+ private static final String ATTRIBUTES_TAG = "attributes";
+
private static final String CREATED = "created";
private static final String EMAIL = "email";
@@ -83,8 +82,12 @@
private static final String LAST_MODIFIED = "lastModified";
+ private static final String LOCK_EXPIRY = "lockExpiry";
+
private static final String PASSWORD = "password";
+ private static final String UID = "uid";
+
private static final String USER_TAG = "user";
private static final String WIKI_NAME = "wikiName";
@@ -185,6 +188,19 @@
}
/**
+ * {@inheritDoc}
+ */
+ public UserProfile findByUid( long uid ) throws NoSuchPrincipalException
+ {
+ UserProfile profile = findByAttribute( UID, Long.toString( uid ) );
+ if ( profile != null )
+ {
+ return profile;
+ }
+ throw new NoSuchPrincipalException( "Not in database: " + uid );
+ }
+
+ /**
* Looks up and returns the first {@link UserProfile}in the user database
* that matches a profile having a given wiki name. If the user database
* does not contain a user with a matching attribute, throws a
@@ -209,6 +225,7 @@
* contain any profiles, this method will return a zero-length
* array.
* @return the WikiNames
+ * @throws WikiSecurityException In case things fail.
*/
public Principal[] getWikiNames() throws WikiSecurityException
{
@@ -216,7 +233,7 @@
{
throw new IllegalStateException( "FATAL: database does not exist" );
}
- Set principals = new HashSet();
+ SortedSet<Principal> principals = new TreeSet<Principal>();
NodeList users = c_dom.getElementsByTagName( USER_TAG );
for( int i = 0; i < users.getLength(); i++ )
{
@@ -232,7 +249,7 @@
principals.add( principal );
}
}
- return (Principal[])principals.toArray( new Principal[principals.size()] );
+ return principals.toArray( new Principal[principals.size()] );
}
/**
@@ -345,7 +362,9 @@
for( int i = 0; i < nodes.getLength(); i++ )
{
Element user = (Element)nodes.item( i );
- io.write( "<" + USER_TAG + " ");
+ io.write( " <" + USER_TAG + " ");
+ io.write( UID );
+ io.write( "=\"" + user.getAttribute( UID ) + "\" " );
io.write( LOGIN_NAME );
io.write( "=\"" + user.getAttribute( LOGIN_NAME ) + "\" " );
io.write( WIKI_NAME );
@@ -360,7 +379,19 @@
io.write( "=\"" + user.getAttribute( CREATED ) + "\" " );
io.write( LAST_MODIFIED );
io.write( "=\"" + user.getAttribute( LAST_MODIFIED ) + "\" " );
- io.write(" />\n");
+ io.write( LOCK_EXPIRY );
+ io.write( "=\"" + user.getAttribute( LOCK_EXPIRY ) + "\" " );
+ io.write( ">" );
+ NodeList attributes = user.getElementsByTagName( ATTRIBUTES_TAG );
+ for ( int j = 0; j < attributes.getLength(); j++ )
+ {
+ Element attribute = (Element)attributes.item( j );
+ String value = extractText( attribute );
+ io.write( "\n <" + ATTRIBUTES_TAG + ">" );
+ io.write( value );
+ io.write( "</" + ATTRIBUTES_TAG + ">" );
+ }
+ io.write("\n </" +USER_TAG + ">\n");
}
io.write("</users>");
io.close();
@@ -411,16 +442,6 @@
}
}
}
-
- /**
- * Determines whether the user database shares user/password data with the
- * web container; always returns <code>false</code>.
- * @see com.ecyrd.jspwiki.auth.user.UserDatabase#isSharedWithContainer()
- */
- public boolean isSharedWithContainer()
- {
- return false;
- }
/**
* @see com.ecyrd.jspwiki.auth.user.UserDatabase#rename(String, String)
@@ -492,31 +513,46 @@
String index = profile.getLoginName();
NodeList users = c_dom.getElementsByTagName( USER_TAG );
Element user = null;
- boolean isNew = true;
for( int i = 0; i < users.getLength(); i++ )
{
Element currentUser = (Element) users.item( i );
if ( currentUser.getAttribute( LOGIN_NAME ).equals( index ) )
{
user = currentUser;
- isNew = false;
break;
}
}
+
+ boolean isNew = false;
+
Date modDate = new Date( System.currentTimeMillis() );
- if ( isNew )
+ if( user == null )
{
+ // Create new user node
profile.setCreated( modDate );
log.info( "Creating new user " + index );
user = c_dom.createElement( USER_TAG );
c_dom.getDocumentElement().appendChild( user );
setAttribute( user, CREATED, c_format.format( profile.getCreated() ) );
+ isNew = true;
+ }
+ else
+ {
+ // To update existing user node, delete old attributes first...
+ NodeList attributes = user.getElementsByTagName( ATTRIBUTES_TAG );
+ for ( int i = 0; i < attributes.getLength(); i++ )
+ {
+ user.removeChild( attributes.item( i ) );
+ }
}
+
setAttribute( user, LAST_MODIFIED, c_format.format( modDate ) );
setAttribute( user, LOGIN_NAME, profile.getLoginName() );
setAttribute( user, FULL_NAME, profile.getFullname() );
setAttribute( user, WIKI_NAME, profile.getWikiName() );
setAttribute( user, EMAIL, profile.getEmail() );
+ Date lockExpiry = profile.getLockExpiry();
+ setAttribute( user, LOCK_EXPIRY, lockExpiry == null ? "" : c_format.format( lockExpiry ) );
// Hash and save the new password if it's different from old one
String newPassword = profile.getPassword();
@@ -525,7 +561,24 @@
String oldPassword = user.getAttribute( PASSWORD );
if ( !oldPassword.equals( newPassword ) )
{
- setAttribute( user, PASSWORD, SHA_PREFIX + getHash( newPassword ) );
+ setAttribute( user, PASSWORD, getHash( newPassword ) );
+ }
+ }
+
+ // Save the attributes as as Base64 string
+ if ( profile.getAttributes().size() > 0 )
+ {
+ try
+ {
+ String encodedAttributes = Serializer.serializeToBase64( profile.getAttributes() );
+ Element attributes = c_dom.createElement( ATTRIBUTES_TAG );
+ user.appendChild( attributes );
+ Text value = c_dom.createTextNode( encodedAttributes );
+ attributes.appendChild( value );
+ }
+ catch ( IOException e )
+ {
+ throw new WikiSecurityException( "Could not save user profile attribute. Reason: " + e.getMessage() );
}
}
@@ -542,7 +595,8 @@
/**
* Private method that returns the first {@link UserProfile}matching a
- * <user> element's supplied attribute.
+ * <user> element's supplied attribute. This method will also
+ * set the UID if it has not yet been set.
* @param matchAttribute
* @param index
* @return the profile, or <code>null</code> if not found
@@ -562,16 +616,52 @@
Element user = (Element) users.item( i );
if ( user.getAttribute( matchAttribute ).equals( index ) )
{
- UserProfile profile = new DefaultUserProfile();
+ UserProfile profile = newProfile();
+
+ // Parse basic attributes
+ profile.setUid( parseLong( user.getAttribute( UID ) ) );
+ if ( profile.getUid() == UID_NOT_SET )
+ {
+ profile.setUid( generateUid( this ) );
+ }
profile.setLoginName( user.getAttribute( LOGIN_NAME ) );
profile.setFullname( user.getAttribute( FULL_NAME ) );
profile.setPassword( user.getAttribute( PASSWORD ) );
profile.setEmail( user.getAttribute( EMAIL ) );
+
+ // Get created/modified timestamps
String created = user.getAttribute( CREATED );
String modified = user.getAttribute( LAST_MODIFIED );
-
profile.setCreated( parseDate( profile, created ) );
profile.setLastModified( parseDate( profile, modified ) );
+
+ // Is the profile locked?
+ String lockExpiry = user.getAttribute( LOCK_EXPIRY );
+ if ( lockExpiry == null || lockExpiry.length() == 0 )
+ {
+ profile.setLockExpiry( null );
+ }
+ else
+ {
+ profile.setLockExpiry( new Date( Long.parseLong( lockExpiry ) ) );
+ }
+
+ // Extract all of the user's attributes (should only be one attributes tag, but you never know!)
+ NodeList attributes = user.getElementsByTagName( ATTRIBUTES_TAG );
+ for ( int j = 0; j < attributes.getLength(); j++ )
+ {
+ Element attribute = (Element)attributes.item( j );
+ String serializedMap = extractText( attribute );
+ try
+ {
+ Map<String,? extends Serializable> map = Serializer.deserializeFromBase64( serializedMap );
+ profile.getAttributes().putAll( map );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Could not parse user profile attributes!", e );
+ }
+ }
return profile;
}
@@ -580,6 +670,29 @@
}
/**
+ * Extracts all of the text nodes that are immediate children of an Element.
+ * @param element the base element
+ * @return the text nodes that are immediate children of the base element, concatenated together
+ */
+ private String extractText( Element element )
+ {
+ String text = "";
+ if ( element.getChildNodes().getLength() > 0 )
+ {
+ NodeList children = element.getChildNodes();
+ for ( int k = 0; k < children.getLength(); k++ )
+ {
+ Node child = children.item( k );
+ if ( child.getNodeType() == Node.TEXT_NODE )
+ {
+ text = text + ((Text)child).getData();
+ }
+ }
+ }
+ return text;
+ }
+
+ /**
* Tries to parse a date using the default format - then, for backwards
* compatibility reasons, tries the platform default.
*
@@ -625,6 +738,16 @@
for( int i = 0; i < users.getLength(); i++ )
{
Element user = (Element) users.item( i );
+
+ // Sanitize UID (and generate a new one if one does not exist)
+ String uid = user.getAttribute( UID ).trim();
+ if ( uid == null || uid.length() == 0 || "-1".equals( uid ) )
+ {
+ uid = String.valueOf( generateUid( this ) );
+ user.setAttribute( UID, uid );
+ }
+
+ // Sanitize dates
String loginName = user.getAttribute( LOGIN_NAME );
String created = user.getAttribute( CREATED );
String modified = user.getAttribute( LAST_MODIFIED );
@@ -656,7 +779,7 @@
}
/**
- * Private method that sets an attibute value for a supplied DOM element.
+ * Private method that sets an attribute value for a supplied DOM element.
* @param element the element whose attribute is to be set
* @param attribute the name of the attribute to set
* @param value the desired attribute value
Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/content/PageRenamer.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/content/PageRenamer.java?rev=682144&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/content/PageRenamer.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/content/PageRenamer.java Sun Aug 3 05:17:34 2008
@@ -0,0 +1,374 @@
+/*
+ JSPWiki - a JSP-based WikiWiki clone.
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+package com.ecyrd.jspwiki.content;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+
+import com.ecyrd.jspwiki.*;
+import com.ecyrd.jspwiki.attachment.Attachment;
+import com.ecyrd.jspwiki.parser.JSPWikiMarkupParser;
+import com.ecyrd.jspwiki.parser.MarkupParser;
+import com.ecyrd.jspwiki.providers.ProviderException;
+
+/**
+ * Provides page renaming functionality. Note that there used to be
+ * a similarly named class in 2.6, but due to unclear copyright, the
+ * class was completely rewritten from scratch for 2.8.
+ *
+ * @since 2.8
+ */
+public class PageRenamer
+{
+
+ private static final Logger log = Logger.getLogger( PageRenamer.class );
+
+ private boolean m_camelCase = false;
+
+ /**
+ * Renames a page.
+ *
+ * @param context The current context.
+ * @param renameFrom The name from which to rename.
+ * @param renameTo The new name.
+ * @param changeReferrers If true, also changes all the referrers.
+ * @return The final new name (in case it had to be modified)
+ * @throws WikiException If the page cannot be renamed.
+ */
+ public String renamePage( WikiContext context,
+ String renameFrom,
+ String renameTo,
+ boolean changeReferrers )
+ throws WikiException
+ {
+ //
+ // Sanity checks first
+ //
+ if( renameFrom == null || renameFrom.length() == 0 )
+ {
+ throw new WikiException( "From name may not be null or empty" );
+ }
+ if( renameTo == null || renameTo.length() == 0 )
+ {
+ throw new WikiException( "To name may not be null or empty" );
+ }
+
+ //
+ // Clean up the "to" -name so that it does not contain anything illegal
+ //
+
+ renameTo = MarkupParser.cleanLink( renameTo.trim() );
+
+ if( renameTo.equals(renameFrom) )
+ {
+ throw new WikiException( "You cannot rename the page to itself" );
+ }
+
+ //
+ // Preconditions: "from" page must exist, and "to" page must not yet exist.
+ //
+ WikiEngine engine = context.getEngine();
+ WikiPage fromPage = engine.getPage( renameFrom );
+
+ if( fromPage == null )
+ {
+ throw new WikiException("No such page "+renameFrom);
+ }
+
+ WikiPage toPage = engine.getPage( renameTo );
+
+ if( toPage != null )
+ {
+ throw new WikiException("Page already exists "+renameTo);
+ }
+
+ //
+ // Options
+ //
+
+ m_camelCase = TextUtil.getBooleanProperty( engine.getWikiProperties(),
+ JSPWikiMarkupParser.PROP_CAMELCASELINKS,
+ m_camelCase );
+
+ //
+ // Do the actual rename by changing from the frompage to the topage, including
+ // all of the attachments
+ //
+
+ engine.getPageManager().getProvider().movePage( renameFrom, renameTo );
+
+ if( engine.getAttachmentManager().attachmentsEnabled() )
+ {
+ engine.getAttachmentManager().getCurrentProvider().moveAttachmentsForPage( renameFrom, renameTo );
+ }
+
+ //
+ // Add a comment to the page notifying what changed. This adds a new revision
+ // to the repo with no actual change.
+ //
+
+ toPage = engine.getPage( renameTo );
+
+ if( toPage == null ) throw new InternalWikiException("Rename seems to have failed for some strange reason - please check logs!");
+
+ toPage.setAttribute( WikiPage.CHANGENOTE, "Renamed from "+fromPage.getName() );
+ toPage.setAuthor( context.getCurrentUser().getName() );
+
+ engine.getPageManager().putPageText( toPage, engine.getPureText( toPage ) );
+
+ //
+ // Update the references
+ //
+
+ engine.getReferenceManager().pageRemoved( fromPage );
+ engine.updateReferences( toPage );
+
+ //
+ // Update referrers first
+ //
+ if( changeReferrers )
+ {
+ updateReferrers( context, fromPage, toPage );
+ }
+
+
+ //
+ // Done, return the new name.
+ //
+ return renameTo;
+ }
+
+ /**
+ * This method finds all the pages which have anything to do with the fromPage and
+ * change any referrers it can figure out in that page.
+ *
+ * @param context WikiContext in which we operate
+ * @param fromPage The old page
+ * @param toPage The new page
+ */
+ @SuppressWarnings("unchecked")
+ private void updateReferrers( WikiContext context, WikiPage fromPage, WikiPage toPage )
+ {
+ WikiEngine engine = context.getEngine();
+ Set<String> referrers = new TreeSet<String>();
+
+ Collection<String> r = engine.getReferenceManager().findReferrers( fromPage.getName() );
+ if( r != null ) referrers.addAll( r );
+
+ try
+ {
+ Collection<Attachment> attachments = engine.getAttachmentManager().listAttachments( fromPage );
+
+ for( Attachment att : attachments )
+ {
+ Collection<String> c = engine.getReferenceManager().findReferrers(att.getName());
+
+ if( c != null ) referrers.addAll(c);
+ }
+ }
+ catch( ProviderException e )
+ {
+ // We will continue despite this error
+ log.error( "Provider error while fetching attachments for rename", e );
+ }
+
+
+ if( referrers.isEmpty() ) return; // No referrers
+
+ for( String pageName : referrers )
+ {
+ WikiPage p = engine.getPage( pageName );
+
+ String sourceText = engine.getPureText( p );
+
+ String newText = replaceReferrerString( context, sourceText, fromPage.getName(), toPage.getName() );
+
+ if( m_camelCase )
+ newText = replaceCCReferrerString( context, newText, fromPage.getName(), toPage.getName() );
+
+ if( !sourceText.equals( newText ) )
+ {
+ p.setAttribute( WikiPage.CHANGENOTE, "Renaming change "+fromPage.getName()+" to "+toPage.getName() );
+ p.setAuthor( context.getCurrentUser().getName() );
+
+ try
+ {
+ engine.getPageManager().putPageText( p, newText );
+ engine.updateReferences( p );
+ }
+ catch( ProviderException e )
+ {
+ //
+ // We fail with an error, but we will try to continue to rename
+ // other referrers as well.
+ //
+ log.error("Unable to perform rename.",e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Replaces camelcase links.
+ */
+ private String replaceCCReferrerString( WikiContext context, String sourceText, String from, String to )
+ {
+ StringBuilder sb = new StringBuilder( sourceText.length()+32 );
+
+ Pattern linkPattern = Pattern.compile( "\\p{Lu}+\\p{Ll}+\\p{Lu}+[\\p{L}\\p{Digit}]*" );
+
+ Matcher matcher = linkPattern.matcher( sourceText );
+
+ int start = 0;
+
+ while( matcher.find(start) )
+ {
+ String match = matcher.group();
+
+ sb.append( sourceText.substring( start, matcher.start() ) );
+
+ int lastOpenBrace = sourceText.lastIndexOf( '[', matcher.start() );
+ int lastCloseBrace = sourceText.lastIndexOf( ']', matcher.start() );
+
+ if( match.equals( from ) && lastCloseBrace >= lastOpenBrace )
+ {
+ sb.append( to );
+ }
+ else
+ {
+ sb.append( match );
+ }
+
+ start = matcher.end();
+ }
+
+ sb.append( sourceText.substring( start ) );
+
+ return sb.toString();
+ }
+
+ private String replaceReferrerString( WikiContext context, String sourceText, String from, String to )
+ {
+ StringBuilder sb = new StringBuilder( sourceText.length()+32 );
+
+ Pattern linkPattern = Pattern.compile( "([\\[\\~]?)\\[([^\\|\\]]*)(\\|)?([^\\|\\]]*)(\\|)?([^\\|\\]]*)\\]" );
+
+ Matcher matcher = linkPattern.matcher( sourceText );
+
+ int start = 0;
+
+ //System.out.println("====");
+ //System.out.println("SRC="+sourceText.trim());
+ while( matcher.find(start) )
+ {
+ char charBefore = (char)-1;
+
+ if( matcher.start() > 0 )
+ charBefore = sourceText.charAt( matcher.start()-1 );
+
+ if( matcher.group(1).length() > 0 || charBefore == '~' || charBefore == '[' )
+ {
+ //
+ // Found an escape character, so I am escaping.
+ //
+ sb.append( sourceText.substring( start, matcher.end() ) );
+ start = matcher.end();
+ continue;
+ }
+
+ String text = matcher.group(2);
+ String link = matcher.group(4);
+ String attr = matcher.group(6);
+
+ /*
+ System.out.println("MATCH="+matcher.group(0));
+ System.out.println(" text="+text);
+ System.out.println(" link="+link);
+ System.out.println(" attr="+attr);
+ */
+ if( link.length() == 0 )
+ {
+ text = replaceSingleLink( context, text, from, to );
+ }
+ else
+ {
+ link = replaceSingleLink( context, link, from, to );
+
+ //
+ // A very simple substitution, but should work for quite a few cases.
+ //
+ text = TextUtil.replaceString( text, from, to );
+ }
+
+ //
+ // Construct the new string
+ //
+ sb.append( sourceText.substring( start, matcher.start() ) );
+ sb.append( "["+text );
+ if( link.length() > 0 ) sb.append( "|" + link );
+ if( attr.length() > 0 ) sb.append( "|" + attr );
+ sb.append( "]" );
+
+ start = matcher.end();
+ }
+
+ sb.append( sourceText.substring( start ) );
+
+ return sb.toString();
+ }
+
+ /**
+ * This method does a correct replacement of a single link, taking into
+ * account anchors and attachments.
+ */
+ private String replaceSingleLink( WikiContext context, String original, String from, String newlink )
+ {
+ int hash = original.indexOf( '#' );
+ int slash = original.indexOf( '/' );
+ String reallink = original;
+
+ if( hash != -1 ) reallink = original.substring( 0, hash );
+ if( slash != -1 ) reallink = original.substring( 0,slash );
+
+ reallink = MarkupParser.cleanLink( reallink );
+
+ // WikiPage p = context.getEngine().getPage( reallink );
+ // WikiPage p2 = context.getEngine().getPage( from );
+
+ // System.out.println(" "+reallink+" :: "+ from);
+ // System.out.println(" "+p+" :: "+p2);
+
+ //
+ // Yes, these point to the same page.
+ //
+ if( reallink.equals(from) )
+ {
+ return newlink + ((hash > 0) ? original.substring( hash ) : "") + ((slash > 0) ? original.substring( slash ) : "") ;
+ }
+
+ return original;
+ }
+}
Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/content/package.html
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/content/package.html?rev=682144&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/content/package.html (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/content/package.html Sun Aug 3 05:17:34 2008
@@ -0,0 +1,13 @@
+<body>
+Provides content management functionality for JSPWiki.
+
+<h2>Package specification</h2>
+
+<p>This package will in 3.0 contain all content management functionality. Currently
+it is a bit in-the-making.</p>
+
+<h2>Related documentation</h2>
+
+TBD.
+
+</body>
\ No newline at end of file