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    package org.apache.james.system.hbase;
020    
021    import java.io.IOException;
022    
023    import org.apache.hadoop.conf.Configuration;
024    import org.apache.hadoop.hbase.HBaseConfiguration;
025    import org.apache.hadoop.hbase.HColumnDescriptor;
026    import org.apache.hadoop.hbase.HTableDescriptor;
027    import org.apache.hadoop.hbase.client.HBaseAdmin;
028    import org.apache.hadoop.hbase.client.HTable;
029    import org.apache.hadoop.hbase.client.HTablePool;
030    import org.apache.james.domainlist.hbase.def.HDomainList;
031    import org.apache.james.rrt.api.RecipientRewriteTable;
032    import org.apache.james.rrt.hbase.def.HRecipientRewriteTable;
033    import org.apache.james.user.api.UsersRepository;
034    import org.apache.james.user.hbase.def.HUsersRepository;
035    
036    /**
037     * Table Pool singleton to get the DomainList, RecipientRewriteTable and UserRepository HBase tables.
038     * 
039     * TODO Two getInstance methods are public, one for the impl, one for the tests. This is not good.
040     */
041    public class TablePool {    
042        
043        private static Configuration configuration;
044        private static TablePool hbaseSchema;
045        private static HTablePool htablePool;
046        
047        /**
048         * Use getInstance to get an instance of the {@link HTablePool}.
049         * 
050         * Don't give any configuration, the default one will be used
051         * via {@link HBaseConfiguration#create(Configuration)}.
052         * 
053         * If you want to create the instance with a specific {@link HBaseConfiguration},
054         * use {@link #getInstance(Configuration)}
055         * 
056         * @return An instance using a default configuration
057         * @throws IOException
058         */
059        public static synchronized TablePool getInstance() throws IOException {
060            return getInstance(HBaseConfiguration.create());
061        }
062    
063        /**
064         * Use getInstance to get an instance of the {@link HTablePool}.
065         * 
066         * You can give at first call a specific {@link HBaseConfiguration} to suit your needs.
067         * 
068         * @param configuration
069         * @return An instance of {@link HTablePool}
070         * @throws IOException
071         */
072        public static synchronized TablePool getInstance(Configuration configuration) throws IOException {
073            if (hbaseSchema == null) {
074                TablePool.configuration = configuration;
075                TablePool.hbaseSchema = new TablePool();
076                TablePool.htablePool = new HTablePool(configuration, 100);
077                ensureTable(HDomainList.TABLE_NAME, HDomainList.COLUMN_FAMILY_NAME);
078                ensureTable(HRecipientRewriteTable.TABLE_NAME, HRecipientRewriteTable.COLUMN_FAMILY_NAME);
079                ensureTable(HUsersRepository.TABLE_NAME, HUsersRepository.COLUMN_FAMILY_NAME);
080            }
081            return hbaseSchema;
082        }
083        
084        /**
085         * Get an instance of the {@link HDomainList} table.
086         * 
087         * @return An instance of {@link HDomainList}
088         */
089        public HTable getDomainlistTable() {
090            return (HTable) htablePool.getTable(HDomainList.TABLE_NAME);
091        }
092    
093        /**
094         * Get an instance of the RecipientRewriteTable table.
095         * 
096         * @return An instance of {@link RecipientRewriteTable}
097         */
098        public HTable getRecipientRewriteTable() {
099            return (HTable) htablePool.getTable(HRecipientRewriteTable.TABLE_NAME);
100        }
101    
102        /**
103         * Get an instance of the UsersRepository table.
104         * 
105         * @return An instance of {@link UsersRepository}
106         */
107        public HTable getUsersRepositoryTable() {
108            return (HTable) htablePool.getTable(HUsersRepository.TABLE_NAME);
109        }
110    
111        /**
112         * Put back the table in the pool after usage.
113         * 
114         * With later HBase versions, we won't have to put back the table in the pool.
115         * See https://issues.apache.org/jira/browse/HBASE-4054
116         * 
117         * @param table
118         */
119        public void putTable(HTable table) {
120            if (table != null) {
121                htablePool.putTable(table);
122            }
123        }
124        
125        /**
126         * Create a table if needed.
127         * 
128         * @param tableName
129         * @param columnFamilyName
130         * @throws IOException
131         */
132        private static void ensureTable(byte[] tableName, byte[] columnFamilyName) throws IOException {
133            HBaseAdmin hbaseAdmin = new HBaseAdmin(configuration);
134            if (! hbaseAdmin.tableExists(tableName)) {
135              HTableDescriptor desc = new HTableDescriptor(tableName);
136              HColumnDescriptor hColumnDescriptor = new HColumnDescriptor(columnFamilyName);
137              hColumnDescriptor.setMaxVersions(1);
138              desc.addFamily(hColumnDescriptor);
139              hbaseAdmin.createTable(desc);
140            }
141        }
142    
143    }