class EntryWrapper<E> implements Entry<K,V> {
        private final Entry<K,V> delegate;

        /**
         * Sole constructor; requires a wrapped {@link Map.Entry} for delegation
         * @param delegate The corresponding entry from the map
         */
        public EntryWrapper(Entry<K,V> delegate) {
            this.delegate = delegate;
        }
        
        /**
         * Delegated to corresponding method in the backing {@link Map.Entry}
         */
        @Override
        public K getKey() {
            return delegate.getKey();
        }
        
        /**
         * Delegated to corresponding method in the backing {@link Map.Entry}
         */
        @Override
        public V getValue() {
            return delegate.getValue();
        }
        
        /**
         * Set the value of the property corresponding to this entry. This
         * method also updates the database as needed depending on the new
         * property value. A null value will cause the property to be deleted
         * from the database.
         * 
         * @param value The new property value
         * @return The old value of the corresponding property
         */
        @Override
        public V setValue(V value) {
            V oldValue = delegate.setValue(value);
            K key = delegate.getKey();
            if (key instanceof String) {
                if (value instanceof String) {
                    if (oldValue == null) {
                        insertProperty((String) key, (String) value);
                    } else if (!value.equals(oldValue)) {
                        updateProperty((String)key,(String)value, (String)oldValue);
                    }
                } else {
                    deleteProperty((String)key, (oldValue instanceof String) ? (String)oldValue : null);
                }
            }
            return oldValue;
        }
    }

    /**
     * Persist a new group property to the database for the current group
     * 
     * @param key Property name
     * @param value Property value
     */
    private synchronized void insertProperty(String key, String value) {
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(INSERT_PROPERTY);
            pstmt.setString(1, group.getName());
            pstmt.setString(2, key);
            pstmt.setString(3, value);
            pstmt.executeUpdate();
        }
        catch (SQLException e) {
            logger.error(e.getMessage(), e);
        }
        finally {
            DbConnectionManager.closeConnection(pstmt, con);
        }

        // Clean up caches.
        DefaultGroupProvider.sharedGroupMetaCache.clear();
        GroupManager.getInstance().propertyAddedPostProcess(group, key);
    }

    /**
     * Update the value of an existing group property for the current group
     * 
     * @param key Property name
     * @param value Property value
     * @param originalValue Original property value
     */
    private synchronized void updateProperty(String key, String value, String originalValue) {<FILL_FUNCTION_BODY>

        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(UPDATE_PROPERTY);
            pstmt.setString(1, value);
            pstmt.setString(2, key);
            pstmt.setString(3, group.getName());
            pstmt.executeUpdate();
        }
        catch (SQLException e) {
            logger.error(e.getMessage(), e);
        }
        finally {
            DbConnectionManager.closeConnection(pstmt, con);
        }

        // Clean up caches.
        DefaultGroupProvider.sharedGroupMetaCache.clear();
        GroupManager.getInstance().propertyModifiedPostProcess(group, key, originalValue);
    
<methods>public non-sealed void <init>() ,public abstract V put(K, V, boolean) <variables>private static final long serialVersionUID