001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.integration.beans; 021 022import java.beans.PropertyEditor; 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.regex.Matcher; 026import java.util.regex.Pattern; 027 028/** 029 * A {@link PropertyEditor} which converts a {@link String} into 030 * a {@link Collection} and vice versa. 031 * 032 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 033 */ 034public class CollectionEditor extends AbstractPropertyEditor { 035 static final Pattern ELEMENT = Pattern.compile("([,\\s]+)|" 036 + // Delimiter 037 "(?<=\")((?:\\\\\"|\\\\'|\\\\\\\\|\\\\ |[^\"])*)(?=\")|" 038 + "(?<=')((?:\\\\\"|\\\\'|\\\\\\\\|\\\\ |[^'])*)(?=')|" + "((?:[^\\\\\\s'\",]|\\\\ |\\\\\"|\\\\')+)"); 039 040 private final Class<?> elementType; 041 042 public CollectionEditor(Class<?> elementType) { 043 if (elementType == null) { 044 throw new IllegalArgumentException("elementType"); 045 } 046 047 this.elementType = elementType; 048 getElementEditor(); 049 setTrimText(false); 050 } 051 052 private PropertyEditor getElementEditor() { 053 PropertyEditor e = PropertyEditorFactory.getInstance(elementType); 054 if (e == null) { 055 throw new IllegalArgumentException("No " + PropertyEditor.class.getSimpleName() + " found for " 056 + elementType.getSimpleName() + '.'); 057 } 058 return e; 059 } 060 061 @Override 062 protected final String toText(Object value) { 063 StringBuilder buf = new StringBuilder(); 064 for (Object v : (Collection<?>) value) { 065 if (v == null) { 066 v = defaultElement(); 067 } 068 069 PropertyEditor e = PropertyEditorFactory.getInstance(v); 070 if (e == null) { 071 throw new IllegalArgumentException("No " + PropertyEditor.class.getSimpleName() + " found for " 072 + v.getClass().getSimpleName() + '.'); 073 } 074 e.setValue(v); 075 // TODO normalize. 076 String s = e.getAsText(); 077 buf.append(s); 078 buf.append(", "); 079 } 080 081 // Remove the last delimiter. 082 if (buf.length() >= 2) { 083 buf.setLength(buf.length() - 2); 084 } 085 return buf.toString(); 086 } 087 088 @Override 089 protected final Object toValue(String text) throws IllegalArgumentException { 090 PropertyEditor e = getElementEditor(); 091 Collection<Object> answer = newCollection(); 092 Matcher m = ELEMENT.matcher(text); 093 boolean matchedDelimiter = true; 094 095 while (m.find()) { 096 if (m.group(1) != null) { 097 matchedDelimiter = true; 098 continue; 099 } 100 101 if (!matchedDelimiter) { 102 throw new IllegalArgumentException("No delimiter between elements: " + text); 103 } 104 105 // TODO escape here. 106 e.setAsText(m.group()); 107 answer.add(e.getValue()); 108 109 matchedDelimiter = false; 110 if (m.group(2) != null || m.group(3) != null) { 111 // Skip the last '"'. 112 m.region(m.end() + 1, m.regionEnd()); 113 } 114 } 115 116 return answer; 117 } 118 119 protected Collection<Object> newCollection() { 120 return new ArrayList<Object>(); 121 } 122 123 protected Object defaultElement() { 124 PropertyEditor e = PropertyEditorFactory.getInstance(elementType); 125 if (e == null) { 126 return null; 127 } 128 129 if (e instanceof AbstractPropertyEditor) { 130 return ((AbstractPropertyEditor) e).defaultValue(); 131 } 132 133 return null; 134 } 135}