001/* 002 * ModeShape (http://www.modeshape.org) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.modeshape.common.text; 017 018import java.text.CharacterIterator; 019import java.text.StringCharacterIterator; 020import org.modeshape.common.annotation.Immutable; 021 022/** 023 * Encoder that escapes characters that are not allowed in JCR names. The mapping defined in Section 3.6.3 of the JSR-283 public 024 * review document: 025 * <table cellspacing="0" cellpadding="1" border="1"> 026 * <tr> 027 * <th>Non-JCR character<br/> 028 * (Unicode code point)</th> 029 * <th>Private use<br/> 030 * Unicode code point</th> 031 * </tr> 032 * <tr> 033 * <td>(U+002A)</td> 034 * <td>U+F02A</td> 035 * </tr> 036 * <tr> 037 * <td>/ (U+002F)</td> 038 * <td>U+F02F</td> 039 * </tr> 040 * <tr> 041 * <td>: (U+003A)</td> 042 * <td>U+F03A</td> 043 * </tr> 044 * <tr> 045 * <td>[ (U+005B)</td> 046 * <td>U+F05B</td> 047 * </tr> 048 * <tr> 049 * <td>] (U+005D)</td> 050 * <td>U+F05D</td> 051 * </tr> 052 * <tr> 053 * <td>| (U+007C)</td> 054 * <td>U+F07C</td> 055 * </tr> 056 * </table> 057 * </p> 058 */ 059@Immutable 060public class Jsr283Encoder implements TextEncoder, TextDecoder { 061 062 public static boolean containsEncodeableCharacters( String str ) { 063 CharacterIterator iter = new StringCharacterIterator(str); 064 for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) { 065 if (c == '*' || c == '/' || c == ':' || c == '[' || c == ']' || c == '|') return true; 066 } 067 return false; 068 069 } 070 071 @Override 072 public String encode( String publicName ) { 073 if (publicName == null) return null; 074 StringBuilder sb = new StringBuilder(); 075 CharacterIterator iter = new StringCharacterIterator(publicName); 076 for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) { 077 char mapped = c; 078 if (c == '*') { 079 mapped = '\uF02A'; 080 } else if (c == '/') { 081 mapped = '\uF02F'; 082 } else if (c == ':') { 083 mapped = '\uF03A'; 084 } else if (c == '[') { 085 mapped = '\uF05B'; 086 } else if (c == ']') { 087 mapped = '\uF05D'; 088 } else if (c == '|') { 089 mapped = '\uF07C'; 090 } 091 sb.append(mapped); 092 } 093 return sb.toString(); 094 } 095 096 @Override 097 public String decode( String jcrNodeName ) { 098 if (jcrNodeName == null) return null; 099 StringBuilder sb = new StringBuilder(); 100 CharacterIterator iter = new StringCharacterIterator(jcrNodeName); 101 for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) { 102 char mapped = c; 103 if (c == '\uF02A') { 104 mapped = '*'; 105 } else if (c == '\uF02F') { 106 mapped = '/'; 107 } else if (c == '\uF03A') { 108 mapped = ':'; 109 } else if (c == '\uF05B') { 110 mapped = '['; 111 } else if (c == '\uF05D') { 112 mapped = ']'; 113 } else if (c == '\uF07C') { 114 mapped = '|'; 115 } 116 sb.append(mapped); 117 118 } 119 return sb.toString(); 120 } 121 122}