/*
* Copyright 2010 Bizosys Technologies Limited
*
* Licensed to the Bizosys Technologies Limited (Bizosys) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The Bizosys 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.bizosys.hsearch.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.bizosys.hsearch.filter.Storable;
import com.bizosys.hsearch.hbase.HReader;
import com.bizosys.hsearch.hbase.HWriter;
import com.bizosys.hsearch.hbase.NV;
import com.bizosys.hsearch.schema.IOConstants;
import com.bizosys.oneline.ApplicationFault;
import com.bizosys.oneline.SystemFault;
import com.bizosys.oneline.util.StringUtils;
/**
* Url shortner reads urlmappings file and applies shortening <br />
* Example (The URL and tab separated short code) <br />
* http://www.bizosys.com/employee.xml/id= 01 <br />
* http://www.bizosys.com/employee? 02 <br />
* http://www.bizosys.com/company.xml/id= 03 <br />
*
* @author Abinasha Karana
*/
public class UrlShortner {
private static UrlShortner instance = null;
public static final UrlShortner getInstance() throws ApplicationFault, SystemFault{
if ( null != instance) return instance;
synchronized (UrlShortner.class) {
if ( null != instance ) return instance;
instance = new UrlShortner();
instance.refresh();
}
return instance;
}
public HashMap<String, String> urls = null;
public HashMap<String, String> codes = null;
private byte[] SHORTNER_KEY = "urlshortner".getBytes();
private UrlShortner() {
}
public void refresh() throws ApplicationFault, SystemFault{
if ( null != urls) urls.clear();
if ( null != codes) codes.clear();
NV nv = new NV(IOConstants.NAME_VALUE_BYTES, IOConstants.NAME_VALUE_BYTES);
try {
RecordScalar scalar = new RecordScalar(SHORTNER_KEY, nv);
HReader.getScalar(IOConstants.TABLE_CONFIG, scalar);
} catch (Exception ex) {
UtilLog.l.warn("UrlMapper: Could not read urlmappings configurations.", ex);
}
if ( null == nv.data) return;
byte[] bytes = nv.data.toBytes();
int bytesT = bytes.length;
int start=0;
List<String> lstUrl = new ArrayList<String>();
List<String> lstCode = new ArrayList<String>();
while ( ( start + 1 ) < bytesT ) {
start = cut(bytes, bytesT, start, '\t', lstUrl);
start = cut(bytes, bytesT, start, '\n', lstCode);
}
int urlT = lstUrl.size();
if ( urlT != lstCode.size())
throw new ApplicationFault("Wrong configuration file.");
if ( urlT == 0 ) return;
urls = new HashMap<String, String>(urlT);
codes = new HashMap<String, String>(urlT);
for (int i=0; i< urlT; i++) {
urls.put(lstUrl.get(i) , lstCode.get(i));
codes.put(lstCode.get(i), lstUrl.get(i));
}
lstCode.clear();
lstUrl.clear();
}
public void persist(Map<String, String> values) throws ApplicationFault, SystemFault{
StringBuilder sb = new StringBuilder();
for (String url : values.keySet()) {
sb.append(url).append('\t').append(values.get(url)).append('\n');
}
NV nv = new NV(IOConstants.NAME_VALUE_BYTES, IOConstants.NAME_VALUE_BYTES);
nv.data = new Storable(sb.toString());
try {
RecordScalar scalar = new RecordScalar(SHORTNER_KEY, nv);
HWriter.getInstance(false).insertScalar(IOConstants.TABLE_CONFIG, scalar);
if ( UtilLog.l.isDebugEnabled() )
UtilLog.l.debug("Url Mapping is saved sucessfully");
} catch (Exception ex) {
UtilLog.l.warn("UrlMapper: Could not save urlmappings configurations.", ex);
}
}
private int cut(byte[] bytes, int bytesT, int start, char sep, List<String> list) {
for( int i=start; i< bytesT; i++) {
if ( bytes[i] != sep) continue;
int len = i - start;
if ( len <= 0 ) continue;
byte[] urlB = new byte[i - start];
System.arraycopy(bytes, start, urlB, 0, len);
list.add(new String(urlB).trim());
return i;
}
return start;
}
/**
* This encodes to the short form of the URL prefix
* @param url URL
* @return Encoded Url
*/
public String encoding(String url) {
if ( StringUtils.isEmpty(url)) return null;
if ( null == urls) return null;
if ( UtilLog.l.isDebugEnabled())
UtilLog.l.debug("UrlShortner encoding:" + url);
if ( urls != null && urls.containsKey(url) ) return urls.get(url);
int lastEqualto = url.lastIndexOf('=');
if ( -1 != lastEqualto) {
lastEqualto = lastEqualto + 1;
String prefix = url.substring(0,lastEqualto);
if ( urls.containsKey(prefix) )
return urls.get(prefix) + '~' + url.substring(lastEqualto) ;
}
//Can I get an exact till the last / character.
int lastSlash = url.lastIndexOf('?');
if ( -1 != lastSlash) {
String prefix = url.substring(0,lastSlash );
if ( urls.containsKey(prefix) )
return urls.get(prefix) + '~' +url.substring(lastSlash) ;
}
return url;
}
/**
* This decodes the short form of the URL prefix
* @param codedUrl coded URL
* @return The decoded url
*/
public String decoding(String codedUrl) {
if ( StringUtils.isEmpty(codedUrl)) return null;
if ( null == codes) return null;
if ( UtilLog.l.isDebugEnabled())
UtilLog.l.debug("UrlShortner decoding:" + codedUrl);
//Is there a direct match
if ( codes.containsKey(codedUrl) ) return codes.get(codedUrl);
int division = codedUrl.lastIndexOf('~');
if ( -1 == division) return codedUrl;
String code = codedUrl.substring(0,division );
if ( codes.containsKey(code) )
return codes.get(code) + codedUrl.substring(division + 1) ;
return codedUrl;
}
}